Project import
diff --git a/libsepol/Android.mk b/libsepol/Android.mk
new file mode 100644
index 0000000..9507496
--- /dev/null
+++ b/libsepol/Android.mk
@@ -0,0 +1,137 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src_files := \
+	src/assertion.c \
+	src/avrule_block.c \
+	src/avtab.c \
+	src/boolean_record.c \
+	src/booleans.c \
+	src/conditional.c \
+	src/constraint.c \
+	src/context.c \
+	src/context_record.c \
+	src/debug.c \
+	src/ebitmap.c \
+	src/expand.c \
+	src/genbools.c \
+	src/genusers.c \
+	src/handle.c \
+	src/hashtab.c \
+	src/hierarchy.c \
+	src/iface_record.c \
+	src/interfaces.c \
+	src/link.c \
+	src/mls.c \
+	src/module.c \
+	src/module_to_cil.c \
+	src/node_record.c \
+	src/nodes.c \
+	src/polcaps.c \
+	src/policydb.c \
+	src/policydb_convert.c \
+	src/policydb_public.c \
+	src/port_record.c \
+	src/ports.c \
+	src/roles.c \
+	src/services.c \
+	src/sidtab.c \
+	src/symtab.c \
+	src/user_record.c \
+	src/users.c \
+	src/util.c \
+	src/write.c
+
+cil_src_files := \
+	cil/src/cil_binary.c \
+	cil/src/cil_build_ast.c \
+	cil/src/cil.c \
+	cil/src/cil_copy_ast.c \
+	cil/src/cil_find.c \
+	cil/src/cil_fqn.c \
+	cil/src/cil_lexer.l \
+	cil/src/cil_list.c \
+	cil/src/cil_log.c \
+	cil/src/cil_mem.c \
+	cil/src/cil_parser.c \
+	cil/src/cil_policy.c \
+	cil/src/cil_post.c \
+	cil/src/cil_reset_ast.c \
+	cil/src/cil_resolve_ast.c \
+	cil/src/cil_stack.c \
+	cil/src/cil_strpool.c \
+	cil/src/cil_symtab.c \
+	cil/src/cil_tree.c \
+	cil/src/cil_verify.c
+
+common_cflags := \
+	-D_GNU_SOURCE \
+	-Wall -W -Wundef \
+	-Wshadow -Wmissing-noreturn \
+	-Wmissing-format-attribute
+
+common_includes := \
+	$(LOCAL_PATH)/include/ \
+	$(LOCAL_PATH)/src/ \
+	$(LOCAL_PATH)/cil/include/ \
+	$(LOCAL_PATH)/cil/src/ \
+
+##
+# "-x c" forces the lex/yacc files to be compiled as c the build system
+# otherwise forces them to be c++. Need to also add an explicit -std because the
+# build system will soon default C++ to -std=c++11.
+yacc_flags := -x c -std=gnu89
+
+##
+# libsepol.so
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) 
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CPPFLAGS := $(yacc_flags)
+LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+##
+# libsepol.a
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) 
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CPPFLAGS := $(yacc_flags)
+LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+##
+# chkcon
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := chkcon
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) 
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := utils/chkcon.c
+LOCAL_SHARED_LIBRARIES := libsepol
+
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGES := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := $(common_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libsepol/COPYING b/libsepol/COPYING
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/libsepol/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  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 library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/libsepol/ChangeLog b/libsepol/ChangeLog
new file mode 100644
index 0000000..95e56d4
--- /dev/null
+++ b/libsepol/ChangeLog
@@ -0,0 +1,886 @@
+	* Fix neverallowxperm checking on attributes, from Jeff Vander Stoep.
+	* Remove libsepol.map when cleaning, from Nicolas Iooss.
+	* Add high-level language line marking support to CIL, from James Carter.
+	* Change logic of bounds checking to match change in kernel, from James Carter.
+	* Fix multiple spelling errors, from Laurent Bigonville.
+	* Only apply bounds checking to source types in rules, from Stephen Smalley.
+	* Fix CIL and not add an attribute as a type in the attr_type_map, from James Carter
+	* Build policy on systems not supporting DCCP protocol, from Richard Haines.
+	* Fix extended permissions neverallow checking, from Jeff Vander Stoep.
+	* Fix CIL neverallow and bounds checking, from James Carter
+	* Android.mk: Add -D_GNU_SOURCE to common_cflags, from Nick Kralevich.
+	* Add support for portcon dccp protocol, from Richard Haines
+	* Fix bug in CIL when resetting classes, from Steve Lawrence
+
+2.5 2016-02-23
+	* Fix unused variable annotations, from Nicolas Iooss.
+	* Fix uninitialized variable in CIL, from Nicolas Iooss.
+	* Validate extended avrules and permissionxs in CIL, from Steve Lawrence.
+	* Add support in CIL for neverallowx, from Steve Lawrence.
+	* Fully expand neverallowxperm rules, from Richard Haines.
+	* Add support for unordered classes to CIL, from Yuli Khodorkovskiy.
+	* Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep.
+	* Improve CIL block and macro call recursion detection, from Steve Lawrence
+	* Fix CIL uninitialized false positive in cil_binary, from Yuli Khodorkovskiy
+	* Provide error in CIL if classperms are empty, from Yuli Khodorkovskiy
+	* Add userattribute{set} functionality to CIL, from Yuli Khodorkovskiy
+	* fix CIL blockinherit copying segfault and add macro restrictions, from Steve Lawrence
+	* fix CIL NULL pointer dereference when copying classpermission/set, from Steve Lawrence
+	* Add CIL support for ioctl whitelists, from Steve Lawrence
+	* Fix memory leak when destroying avtab, from Steve Lawrence
+	* Replace sscanf in module_to_cil, from Yuli Khodorkovskiy.
+	* Improve CIL resolution error messages, from Steve Lawrence
+	* Fix policydb_read for policy versions < 24, from Stephen Smalley.
+	* Added CIL bounds checking and refactored CIL Neverallow checking, from James Carter
+	* Refactored libsepol Neverallow and bounds (hierarchy) checking, from James Carter
+	* Treat types like an attribute in the attr_type_map, from James Carter
+	* Add new ebitmap function named ebitmap_match_any(), from James Carter
+	* switch operations to extended perms, from Jeff Vander Stoep.
+	* Write auditadm_r and secadm_r roles to base module when writing CIL, from Steve Lawrence
+	* Fix module to CIL to only associate declared roleattributes with in-scope types, from Steve Lawrence
+	* Don't allow categories/sensitivities inside blocks in CIL, from Yuli Khodorkovskiy.
+	* Replace fmemopen() with internal function in libsepol, from James Carter.
+	* Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy.
+	* Binary modules do not support ioctl rules, from Stephen Smalley.
+	* Add support for ioctl command whitelisting, from Jeff Vander Stoep.
+	* Don't use symbol versioning for static object files, from Yuli Khodorkovskiy.
+	* Add sepol_module_policydb_to_cil(), sepol_module_package_to_cil(), and sepol_ppfile_to_module_package(), from James Carter.
+	* Move secilc out of libsepol, from Yuli Khodorkovskiy.
+	* fix building Xen policy with devicetreecon, and add devicetreecon
+	  CIL documentation, from Richard Haines.
+	* bool_copy_callback set state on creation, from Thomas Hurd.
+	* Add device tree ocontext nodes to Xen policy, from Daniel De Graaf.
+	* Widen Xen IOMEM context entries, from Daniel De Graaf.
+	* Update CIL documentation, from Richard Haines
+	* Fix error path in mls_semantic_level_expand(), from Chris PeBenito.
+	* Fix MacOS X build, from Stephen Smalley.
+	* Enabling building CIL in Android, from Stephen Smalley.
+	* Update to latest CIL, includes new name resolution and fixes ordering
+	  issues with blockinherit statements, and bug fixes
+
+2.4 2015-02-02
+	* Remove assumption that SHLIBDIR is ../../ relative to LIBDIR, from Steve
+	  Lawrence
+	* Fix bugs found by hardened gcc flags, from Nicolas Iooss.
+	* Build CIL into libsepol. libsepol can be built without CIL by setting the
+	  DISABLE_CIL flag to 'y', from Steve Lawrence
+	* Add an API function to set target_platform, from Steve Lawrence
+	* Report all neverallow violations, from Stephen Smalley
+	* Improve check_assertions performance through hash tweaks from John Brooks.
+	* Allow libsepol C++ static library on device from Daniel Cashman.
+
+2.3 2014-05-06
+	* Improve error message for name-based transition conflicts.
+	* Revert libsepol: filename_trans: use some better sorting to compare and merge.
+	* Report source file and line information for neverallow failures.
+	* Fix valgrind errors in constraint_expr_eval_reason from Richard Haines.
+	* Add sepol_validate_transition_reason_buffer function from Richard Haines.
+
+2.2 2013-10-30
+	* Allow constraint denial cause to be determined from Richard Haines.
+	  - Add kernel policy version 29.
+	  - Add modular policy version 17.
+	  - Add sepol_compute_av_reason_buffer(), sepol_string_to_security_class(), sepol_string_to_av_perm().
+	* Support overriding Makefile RANLIB from Sven Vermeulen.
+	* Fix man pages from Laurent Bigonville.
+
+2.1.9 2013-02-01
+	* filename_trans: use some better sorting to compare and merge
+	* coverity fixes
+	* implement default type policy syntax
+	* Fix memory leak issues found by Klocwork
+
+2.1.8 2012-09-13
+	* fix neverallow checking on attributes
+	* Move context_copy() after switch block in ocontext_copy_*().
+	* check for missing initial SID labeling statement.
+	* Add always_check_network policy capability
+	* role_fix_callback skips out-of-scope roles during expansion.
+
+2.1.7 2012-06-28
+	* reserve policycapability for redhat testing of ptrace child
+	* cosmetic changes to make the source easier to read
+	* prepend instead of append to filename_trans list
+	* Android/MacOS X build support
+
+2.1.6 2012-04-23
+	* allocate enough space to hold filename in trans rules
+
+2.1.5 2012-03-28
+	* checkpolicy: implement new default labeling behaviors
+
+2.1.4 2011-10-03
+	* regenerate .pc on VERSION change
+	* Move ebitmap_* functions from mcstrans to libsepol
+	* expand: do filename_trans type comparison on mapped representation
+
+2.1.3 2011-09-15
+	* Skip writing role attributes for policy.X and
+	* Indicate when boolean is indeed a tunable.
+	* Separate tunable from boolean during compile.
+	* Write and read TUNABLE flags in related
+	* Copy and check the cond_bool_datum_t.flags during link.
+	* Permanently discard disabled branches of tunables in
+	* Skip tunable identifier and cond_node_t in expansion.
+	* Create a new preserve_tunables flag
+	* Preserve tunables when required by semodule program.
+	* setools expects expand_module_avrules to be an exported
+	* tree: default make target to all not
+
+2.1.2 2011-08-03
+	* Only call role_fix_callback for base.p_roles during expansion.
+	* use mapped role number instead of module role number
+
+2.1.1 2011-08-01
+	* Minor fix to reading policy with filename transition rules
+
+2.1.0 2011-07-27
+	* Release, minor version bump
+
+2.0.46 2011-07-25
+	* Add role attribute support by Harry Ciao
+
+2.0.45 2011-05-02
+	* Warn if filename_trans rules are dropped by Steve Lawrence.
+
+2.0.44 2011-04-13
+	* Fixes for new role_transition class field by Eric Paris.
+	* Add libsepol support for filename_trans rules by Eric Paris.
+
+2.0.43 2011-04-11
+	* Add new class field in role_transition by Harry Ciao.
+
+2.0.42 2010-12-16
+	* Fix compliation under GCC 4.6 by Justin Mattock
+
+2.0.41 2009-11-18
+	* Fixed typo in error message from Manoj Srivastava.
+
+2.0.40 2009-10-29
+	* Add pkgconfig file from Eamon Walsh.
+
+2.0.39 2009-10-14
+	* Add support for building Xen policies from Paul Nuzzi.
+
+2.0.38 2009-09-01
+	* Check last offset in the module package against the file size.
+	Reported by Manoj Srivastava for bug filed by Max Kellermann.
+
+2.0.37 2009-07-07
+	* Add method to check disable dontaudit flag from Christopher Pardy.
+
+2.0.36 2009-03-25
+	* Fix boolean state smashing from Joshua Brindle.
+
+2.0.35 2009-02-19
+        * Fix alias field in module format, caused by boundary format change
+          from Caleb Case.
+
+2.0.34 2008-10-09
+	* Add bounds support from KaiGai Kohei.
+	* Fix invalid aliases bug from Joshua Brindle.
+
+2.0.33 2008-09-29
+	* Revert patch that removed expand_rule.
+
+2.0.32 2008-07-07
+	* Allow require then declare in the source policy from Joshua Brindle.
+
+2.0.31 2008-06-13
+	* Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley.
+
+2.0.30 2008-06-06
+	* Fix endianness bug in the handling of network node addresses from Stephen Smalley.
+	  Only affects big endian platforms.
+	  Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc.
+
+2.0.29 2008-05-27
+	* Merge user and role mapping support from Joshua Brindle.
+
+2.0.28 2008-05-05
+	* Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley.
+
+2.0.27 2008-04-18
+	* Belatedly merge test for policy downgrade from Todd Miller.
+
+2.0.26 2008-03-24
+	* Add permissive domain support from Eric Paris.
+
+2.0.25 2008-03-04
+	* Drop unused ->buffer field from struct policy_file.
+
+2.0.24 2008-03-04
+	* Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller.
+
+2.0.23 2008-02-28
+	* Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley.
+
+2.0.22 2008-02-28
+	* Add support for open_perms policy capability from Eric Paris.
+
+2.0.21 2008-02-20
+	* Fix invalid memory allocation in policydb_index_others() from Jason Tang.
+
+2.0.20 2008-02-04
+	* Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley.
+
+2.0.19 2008-02-02
+	* Add support for consuming avrule_blocks during expansion to reduce
+	  peak memory usage from Joshua Brindle.
+
+2.0.18 2008-01-02
+	* Added support for policy capabilities from Todd Miller.
+
+2.0.17 2007-12-21
+	* Prevent generation of policy.18 with MLS enabled from Todd Miller.
+
+2.0.16 2007-12-07
+	* print module magic number in hex on mismatch, from Todd Miller.
+
+2.0.15 2007-11-29
+	* clarify and reduce neverallow error reporting from Stephen Smalley.
+
+2.0.14 2007-11-05
+	* Reject self aliasing at link time from Stephen Smalley.
+
+2.0.13 2007-11-05
+	* Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley.
+
+2.0.12 2007-10-11
+	* Fixed bug in require checking from Stephen Smalley.
+	* Added user hierarchy checking from Todd Miller.	
+
+2.0.11 2007-09-24
+	* Pass CFLAGS to CC even on link command, per Dennis Gilmore.
+
+2.0.10 2007-09-18
+	* Merged support for the handle_unknown policydb flag from Eric Paris.
+
+2.0.9 2007-08-29
+	* Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper.
+
+2.0.8 2007-08-28
+	* Fixed module_package_read_offsets bug introduced by the prior patch.
+
+2.0.7 2007-08-23
+	* Eliminate unaligned accesses from policy reading code from Stephen Smalley.
+
+2.0.6 2007-08-16
+	* Allow dontaudits to be turned off during policy expansion from
+	  Joshua Brindle.
+
+2.0.5 2007-08-01
+	* Fix sepol_context_clone to handle a NULL context correctly.
+          This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL)
+	  to set the file context entry to "<<none>>".
+
+2.0.4 2007-06-20
+	* Merged error handling patch from Eamon Walsh.
+
+2.0.3 2007-04-13
+	* Merged add boolmap argument to expand_module_avrules() from Chris PeBenito.
+
+2.0.2 2007-03-30
+	* Merged fix from Karl to remap booleans at expand time to 
+	  avoid holes in the symbol table.
+
+2.0.1 2007-02-06
+	* Merged libsepol segfault fix from Stephen Smalley for when
+	  sensitivities are required but not present in the base.
+	
+2.0.0 2007-02-01
+	* Merged patch to add errcodes.h to libsepol by Karl MacMillan.
+	
+1.16.0 2007-01-18
+	* Updated version for stable branch.
+
+1.15.3 2006-11-27
+	* Merged patch to compile wit -fPIC instead of -fpic from
+	  Manoj Srivastava to prevent hitting the global offest table
+	  limit. Patch changed to include libselinux and libsemanage in
+	  addition to libselinux.
+1.15.2 2006-10-31
+	* Merged fix from Karl MacMillan for a segfault when linking
+	  non-MLS modules with users in them.
+
+1.15.1 2006-10-24
+	* Merged fix for version comparison that was preventing range
+	  transition rules from being written for a version 5 base policy
+	  from Darrel Goeddel.
+
+1.14 2006-10-17
+	* Updated version for release.
+
+1.12.28 2006-09-28
+	* Build libsepol's static object files with -fpic
+
+1.12.27 2006-09-28
+	* Merged mls user and range_transition support in modules
+	  from Darrel Goeddel
+
+1.12.26 2006-09-05
+	* Merged range transition enhancements and user format changes
+	  Darrel Goeddel
+
+1.12.25 2006-08-24
+	* Merged conditionally expand neverallows patch from Jeremy Mowery.
+	* Merged refactor expander patch from Jeremy Mowery.
+
+1.12.24 2006-08-03
+	* Merged libsepol unit tests from Joshua Brindle.
+
+1.12.23 2006-08-03
+	* Merged symtab datum patch from Karl MacMillan.
+
+1.12.22 2006-08-03
+	* Merged netfilter contexts support from Chris PeBenito.
+
+1.12.21 2006-07-28
+	* Merged helpful hierarchy check errors patch from Joshua Brindle.
+
+1.12.20 2006-07-25
+	* Merged semodule_deps patch from Karl MacMillan.
+	  This adds source module names to the avrule decls.
+
+1.12.19 2006-06-29
+	* Lindent.
+
+1.12.18 2006-06-26
+	* Merged optionals in base take 2 patch set from Joshua Brindle.
+
+1.12.17 2006-05-30
+	* Revert 1.12.16.
+
+1.12.16 2006-05-30
+	* Merged cleaner fix for bool_ids overflow from Karl MacMillan,
+	  replacing the prior patch.
+
+1.12.15 2006-05-30
+	* Merged fixes for several memory leaks in the error paths during
+	  policy read from Serge Hallyn.
+
+1.12.14 2006-05-25
+	* Fixed bool_ids overflow bug in cond_node_find and cond_copy_list,
+	  based on bug report and suggested fix by Cedric Roux.
+
+1.12.13 2006-05-24
+	* Merged sens_copy_callback, check_role_hierarchy_callback,
+	  and node_from_record fixes from Serge Hallyn.
+
+1.12.12 2006-05-22
+	* Added sepol_policydb_compat_net() interface for testing whether
+	  a policy requires the compatibility support for network checks
+	  to be enabled in the kernel.
+
+1.12.11 2006-05-17
+	* Merged patch to initialize sym_val_to_name arrays from Kevin Carr.
+	  Reworked to use calloc in the first place, and converted some other
+	  malloc/memset pairs to calloc calls.
+
+1.12.10 2006-05-08
+	* Merged patch to revert role/user decl upgrade from Karl MacMillan.
+
+1.12.9 2006-05-08
+	* Dropped tests from all Makefile target.
+
+1.12.8 2006-05-05
+	* Merged fix warnings patch from Karl MacMillan.
+
+1.12.7 2006-05-05
+	* Merged libsepol test framework patch from Karl MacMillan.
+
+1.12.6 2006-04-28
+	* Fixed cond_normalize to traverse the entire cond list at link time.
+
+1.12.5 2006-04-03
+	* Merged fix for leak of optional package sections from Ivan Gyurdiev.
+
+1.12.4 2006-03-29
+	* Generalize test for bitmap overflow in ebitmap_set_bit.
+
+1.12.3 2006-03-27
+	* Fixed attr_convert_callback and expand_convert_type_set
+	  typemap bug.
+
+1.12.2 2006-03-24
+	* Fixed avrule_block_write num_decls endian bug.
+
+1.12.1 2006-03-20
+	* Fixed sepol_module_package_write buffer overflow bug.
+
+1.12 2006-03-14
+	* Updated version for release.
+
+1.11.20 2006-03-08
+	* Merged cond_evaluate_expr fix from Serge Hallyn (IBM).
+	* Fixed bug in copy_avrule_list reported by Ivan Gyurdiev.
+
+1.11.19 2006-02-21
+	* Merged sepol_policydb_mls_enabled interface and error handling
+	  changes from Ivan Gyurdiev.
+	
+1.11.18 2006-02-16
+	* Merged node_expand_addr bugfix and node_compare* change from
+	  Ivan Gyurdiev.
+
+1.11.17 2006-02-15
+	* Merged nodes, ports: always prepend patch from Ivan Gyurdiev.
+	* Merged bug fix patch from Ivan Gyurdiev.
+
+1.11.16 2006-02-14
+	* Added a defined flag to level_datum_t for use by checkpolicy.
+
+1.11.15 2006-02-14
+	* Merged nodecon support patch from Ivan Gyurdiev.
+	* Merged cleanups patch from Ivan Gyurdiev.	
+
+1.11.14 2006-02-13
+	* Merged optionals in base patch from Joshua Brindle.
+	
+1.11.13 2006-02-07
+	* Merged seuser/user_extra support patch from Joshua Brindle.
+	* Merged fix patch from Ivan Gyurdiev.
+
+1.11.12 2006-02-02
+	* Merged clone record on set_con patch from Ivan Gyurdiev.	
+
+1.11.11 2006-02-01
+	* Merged assertion copying bugfix from Joshua Brindle.
+	* Merged sepol_av_to_string patch from Joshua Brindle.
+
+1.11.10 2006-01-30
+	* Merged cond_expr mapping and package section count bug fixes
+	  from Joshua Brindle.
+	* Merged improve port/fcontext API patch from Ivan Gyurdiev.	
+	* Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev.
+
+1.11.9 2006-01-12
+	* Merged size_t -> unsigned int patch from Ivan Gyurdiev.
+
+1.11.8 2006-01-09
+	* Merged 2nd const in APIs patch from Ivan Gyurdiev.
+
+1.11.7 2006-01-06
+	* Merged const in APIs patch from Ivan Gyurdiev.
+	* Merged compare2 function patch from Ivan Gyurdiev.
+
+1.11.6 2006-01-06
+	* Fixed hierarchy checker to only check allow rules.
+
+1.11.5 2006-01-05
+	* Merged further fixes from Russell Coker, specifically:
+	  - av_to_string overflow checking
+	  - sepol_context_to_string error handling
+	  - hierarchy checking memory leak fixes and optimizations
+	  - avrule_block_read variable initialization
+	* Marked deprecated code in genbools and genusers.
+
+1.11.4 2006-01-05
+	* Merged bugfix for sepol_port_modify from Russell Coker.
+
+1.11.3 2006-01-05
+	* Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev.
+	* Merged port ordering patch from Ivan Gyurdiev.
+
+1.11.2 2006-01-04
+	* Merged patch series from Ivan Gyurdiev.
+	  This includes patches to:
+	  - support ordering of records in compare function
+	  - enable port interfaces
+	  - add interfaces for context validity and range checks
+	  - add include guards
+
+1.11.1 2005-12-16
+	* Fixed mls_range_cpy bug.
+
+1.10 2005-12-07
+	* Updated version for release.
+
+1.9.42 2005-12-05
+	* Dropped handle from user_del_role interface.	
+
+1.9.41 2005-11-28
+	* Merged remove defrole from sepol patch from Ivan Gyurdiev.
+
+1.9.40 2005-11-15
+	* Merged module function and map file cleanup from Ivan Gyurdiev.
+	* Merged MLS and genusers cleanups from Ivan Gyurdiev.
+
+1.9.39 2005-11-09
+	Prepare for removal of booleans* and *.users files.
+	* Cleaned up sepol_genbools to not regenerate the image if
+	  there were no changes in the boolean values, including the
+	  degenerate case where there are no booleans or booleans.local
+	  files.
+	* Cleaned up sepol_genusers to not warn on missing local.users.
+	
+1.9.38 2005-11-08
+	* Removed sepol_port_* from libsepol.map, as the port interfaces
+	  are not yet stable.
+
+1.9.37 2005-11-04
+	* Merged context destroy cleanup patch from Ivan Gyurdiev.
+
+1.9.36 2005-11-03
+	* Merged context_to_string interface change patch from Ivan Gyurdiev.
+
+1.9.35 2005-11-01
+	* Added src/dso.h and src/*_internal.h.
+	  Added hidden_def for exported symbols used within libsepol.
+	  Added hidden for symbols that should not be exported by
+	  the wildcards in libsepol.map.
+
+1.9.34 2005-10-31
+	* Merged record interface, record bugfix, and set_roles patches 
+	  from Ivan Gyurdiev.
+
+1.9.33 2005-10-27
+	* Merged count specification change from Ivan Gyurdiev.	
+
+1.9.32 2005-10-26
+	* Added further checking and error reporting to 
+	  sepol_module_package_read and _info.
+
+1.9.31 2005-10-26
+	* Merged sepol handle passing, DEBUG conversion, and memory leak
+	  fix patches from Ivan Gyurdiev.
+
+1.9.30 2005-10-25
+	* Removed processing of system.users from sepol_genusers and
+	  dropped delusers logic.
+
+1.9.29 2005-10-25
+	* Removed policydb_destroy from error path of policydb_read,
+	  since create/init/destroy/free of policydb is handled by the
+	  caller now.
+	* Fixed sepol_module_package_read to handle a failed policydb_read
+	  properly.
+
+1.9.28 2005-10-25
+	* Merged query/exists and count patches from Ivan Gyurdiev.
+
+1.9.27 2005-10-25
+	* Merged fix for pruned types in expand code from Joshua Brindle.
+	* Merged new module package format code from Joshua Brindle.
+
+1.9.26 2005-10-24
+	* Merged context interface cleanup, record conversion code, 
+	  key passing, and bug fix patches from Ivan Gyurdiev.               
+
+1.9.25 2005-10-21
+	* Merged users cleanup patch from Ivan Gyurdiev.
+
+1.9.24 2005-10-21
+	* Merged user record memory leak fix from Ivan Gyurdiev.
+	* Merged reorganize users patch from Ivan Gyurdiev.
+
+1.9.23 2005-10-19
+	* Added check flag to expand_module() to control assertion
+	  and hierarchy checking on expansion.
+
+1.9.22 2005-10-19
+	* Reworked check_assertions() and hierarchy_check_constraints()
+	  to take handles and use callback-based error reporting.
+	* Changed expand_module() to call check_assertions() and 
+	  hierarchy_check_constraints() prior to returning the expanded
+	  policy.
+
+1.9.21 2005-10-18
+	* Changed sepol_module_package_set_file_contexts to copy the
+	  file contexts data since it is internally managed.
+
+1.9.20 2005-10-18
+	* Added sepol_policy_file_set_handle interface to associate
+	  a handle with a policy file.
+	* Added handle argument to policydb_from_image/to_image.
+	* Added sepol_module_package_set_file_contexts interface.
+	* Dropped sepol_module_package_create_file interface.
+	* Reworked policydb_read/write, policydb_from_image/to_image, 
+	  and sepol_module_package_read/write to use callback-based error
+	  reporting system rather than DEBUG.  
+
+1.9.19 2005-10-17
+	* Reworked link_packages, link_modules, and expand_module to use
+	callback-based error reporting system rather than error buffering.
+
+1.9.18 2005-10-14
+	* Merged conditional expression mapping fix in the module linking
+	code from Joshua Brindle.
+
+1.9.17 2005-10-13
+	* Hid sepol_module_package type definition, and added get interfaces.
+
+1.9.16 2005-10-13
+	* Merged new callback-based error reporting system from Ivan
+	Gyurdiev.
+
+1.9.15 2005-10-13
+	* Merged support for require blocks inside conditionals from
+	Joshua Brindle (Tresys).
+
+1.9.14 2005-10-07
+	* Fixed use of policydb_from_image/to_image to ensure proper
+	init of policydb.
+
+1.9.13 2005-10-07
+	* Isolated policydb internal headers under <sepol/policydb/*.h>.
+	These headers should only be used by users of the static libsepol.
+	Created new <sepol/policydb.h> with new public types and interfaces
+	for shared libsepol.
+	Created new <sepol/module.h> with public types and interfaces moved
+	or wrapped from old module.h, link.h, and expand.h, adjusted for
+	new public types for policydb and policy_file.
+	Added public interfaces to libsepol.map.
+	Some implementation changes visible to users of the static libsepol:
+	1) policydb_read no longer calls policydb_init.
+	Caller must do so first.
+	2) policydb_init no longer takes policy_type argument.
+	Caller must set policy_type separately.
+	3) expand_module automatically enables the global branch.  
+	Caller no longer needs to do so.
+	4) policydb_write uses the policy_type and policyvers from the 
+	policydb itself, and sepol_set_policyvers() has been removed.
+	
+1.9.12 2005-10-06
+	* Merged function renaming and static cleanup from Ivan Gyurdiev.
+
+1.9.11 2005-10-05
+	* Merged bug fix for check_assertions handling of no assertions
+	from Joshua Brindle (Tresys).
+	
+1.9.10 2005-10-04
+	* Merged iterate patch from Ivan Gyurdiev.
+
+1.9.9 2005-10-03
+	* Merged MLS in modules patch from Joshua Brindle (Tresys).
+
+1.9.8 2005-09-30
+	* Merged pointer typedef elimination patch from Ivan Gyurdiev.
+	* Merged user list function, new mls functions, and bugfix patch
+	  from Ivan Gyurdiev.
+
+1.9.7 2005-09-28
+	* Merged sepol_get_num_roles fix from Karl MacMillan (Tresys).
+
+1.9.6 2005-09-23
+	* Merged bug fix patches from Joshua Brindle (Tresys).
+
+1.9.5 2005-09-21
+	* Merged boolean record and memory leak fix patches from Ivan
+	Gyurdiev.
+
+1.9.4 2005-09-19
+	* Merged interface record patch from Ivan Gyurdiev.
+
+1.9.3 2005-09-14
+	* Merged fix for sepol_enable/disable_debug from Ivan
+	Gyurdiev.
+
+1.9.2 2005-09-14
+	* Merged stddef.h patch and debug conversion patch from 
+	Ivan Gyurdiev.
+
+1.9.1 2005-09-09
+	* Fixed expand_avtab and expand_cond_av_list to keep separate
+	entries with identical keys but different enabled flags.
+
+1.8 2005-09-06
+	* Updated version for release.
+
+1.7.24 2005-08-31
+	* Fixed symtab_insert return value for duplicate declarations.
+
+1.7.23 2005-08-31
+	* Merged fix for memory error in policy_module_destroy from
+	Jason Tang (Tresys).
+
+1.7.22 2005-08-26
+	* Merged fix for memory leak in sepol_context_to_sid from
+	Jason Tang (Tresys).
+
+1.7.21 2005-08-25
+	* Merged fixes for resource leaks on error paths and
+	  change to scope_destroy from Joshua Brindle (Tresys).
+
+1.7.20 2005-08-23
+	* Merged more fixes for resource leaks on error paths 
+	  from Serge Hallyn (IBM).  Bugs found by Coverity. 
+
+1.7.19 2005-08-19
+	* Changed to treat all type conflicts as fatal errors.
+
+1.7.18 2005-08-18
+	* Merged several error handling fixes from 
+	  Serge Hallyn (IBM).  Bugs found by Coverity.	
+
+1.7.17 2005-08-15
+	* Fixed further memory leaks found by valgrind.
+
+1.7.16 2005-08-15
+	* Fixed several memory leaks found by valgrind.
+
+1.7.15 2005-08-12
+	* Fixed empty list test in cond_write_av_list.  Bug found by
+	  Coverity, reported by Serge Hallyn (IBM).
+	* Merged patch to policydb_write to check errors 
+	  when writing the type->attribute reverse map from
+	  Serge Hallyn (IBM).  Bug found by Coverity.
+	* Fixed policydb_destroy to properly handle NULL type_attr_map
+	  or attr_type_map.
+
+1.7.14 2005-08-12
+	* Fixed use of uninitialized data by expand_avtab_node by
+	  clearing type_val_to_struct in policydb_index_others.
+
+1.7.13 2005-08-11
+	* Improved memory use by SELinux by both reducing the avtab 
+	  node size and reducing the number of avtab nodes (by not
+	  expanding attributes in TE rules when possible).  Added
+	  expand_avtab and expand_cond_av_list functions for use by
+	  assertion checker, hierarchy checker, compatibility code,
+	  and dispol.  Added new inline ebitmap operators and converted
+	  existing users of ebitmaps to the new operators for greater 
+	  efficiency.
+	  Note:  The binary policy format version has been incremented to 
+	  version 20 as a result of these changes.
+
+1.7.12 2005-08-10
+	* Fixed bug in constraint_node_clone handling of name sets.
+
+1.7.11 2005-08-08
+	* Fix range_trans_clone to map the type values properly.
+
+1.7.10 2005-08-02
+	* Merged patch to move module read/write code from libsemanage
+	  to libsepol from Jason Tang (Tresys).
+
+1.7.9 2005-08-02
+	* Enabled further compiler warning flags and fixed them.
+
+1.7.8 2005-08-02
+	* Merged user, context, port records patch from Ivan Gyurdiev.
+	* Merged key extract function patch from Ivan Gyurdiev.
+
+1.7.7 2005-07-27
+	* Merged mls_context_to_sid bugfix from Ivan Gyurdiev.
+
+1.7.6 2005-07-26
+	* Merged context reorganization, memory leak fixes, 
+	  port and interface loading, replacements for genusers and
+	  genbools, debug traceback, and bugfix patches from Ivan Gyurdiev.
+	* Merged uninitialized variable bugfix from Dan Walsh.
+
+1.7.5 2005-07-18
+	* Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat).
+	* Removed genpolbools and genpolusers utilities.
+
+1.7.4 2005-07-18
+	* Merged hierarchy check fix from Joshua Brindle (Tresys).
+
+1.7.3 2005-07-13
+	* Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat).
+
+1.7.2 2005-07-11
+	* Merged genbools debugging message cleanup from Red Hat.
+
+1.7.1 2005-07-06
+	* Merged loadable module support from Tresys Technology.
+
+1.6 2005-06-20
+	* Updated version for release.
+
+1.5.10 2005-05-19
+	* License changed to LGPL v2.1, see COPYING.
+
+1.5.9 2005-05-16
+	* Added sepol_genbools_policydb and sepol_genusers_policydb for
+	  audit2why.
+
+1.5.8 2005-05-13
+	* Added sepol_ prefix to Flask types to avoid 
+	  namespace collision with libselinux.
+
+1.5.7 2005-05-13
+	* Added sepol_compute_av_reason() for audit2why.
+
+1.5.6 2005-04-25
+	* Fixed bug in role hierarchy checker.
+
+1.5.5 2005-04-13
+	* Merged hierarchical type/role patch from Tresys Technology.
+	* Merged MLS fixes from Darrel Goeddel of TCS.
+
+1.5.4 2005-04-13
+	* Changed sepol_genusers to not delete users by default,
+	and added a sepol_set_delusers function to enable deletion.
+	Also, removed special case handling of system_u and user_u.
+	
+1.5.3 2005-03-29
+	* Merged booleans.local patch from Dan Walsh.
+
+1.5.2 2005-03-16
+	* Added man page for sepol_check_context.
+
+1.5.1 2005-03-15
+	* Added man page for sepol_genusers function.
+	* Merged man pages for genpolusers and chkcon from Manoj Srivastava.
+
+1.4 2005-03-09
+	* Updated version for release.
+
+1.3.8 2005-03-08
+	* Cleaned up error handling in sepol_genusers and sepol_genbools.
+
+1.3.7 2005-02-28
+	* Merged sepol_debug and fclose patch from Dan Walsh.
+
+1.3.6 2005-02-22
+	* Changed sepol_genusers to also use getline and correctly handle
+	  EOL.
+
+1.3.5 2005-02-17
+	* Merged range_transition support from Darrel Goeddel (TCS).
+
+1.3.4 2005-02-16
+	* Added sepol_genusers function.
+
+1.3.3 2005-02-14
+	* Merged endianness and compute_av patches from Darrel Goeddel (TCS).
+
+1.3.2 2005-02-09
+	* Changed relabel Makefile target to use restorecon.
+
+1.3.1 2005-01-26
+	* Merged enhanced MLS support from Darrel Goeddel (TCS).
+
+1.2.1 2005-01-19
+	* Merged build fix patch from Manoj Srivastava.
+
+1.2 2004-10-07
+	* MLS build fixes.
+	* Added sepol_set_policydb_from_file and sepol_check_context for setfiles.
+
+1.0 2004-08-19
+	* Initial public release.
+
+0.4 2004-08-13
+	* Merged patch from Dan Walsh to ignore case on booleans.
+	* Changed sepol_genbools* to preserve the original policy version.
+	* Replaced exported global variables with set functions. 
+	* Moved genpolbools utility from checkpolicy to libsepol.
+	* Added man pages for sepol_genbools* and genpolbools.
+
+0.3 2004-08-10
+	* Added ChangeLog, COPYING, spec file.
+	* Added sepol_genbools_array() for load_policy.
+	* Created libsepol.map to limit exported symbols in shared library. 
+
+0.2 2004-08-09
+	* Exported other functions for checkpolicy and friends.
+	* Renamed service and sidtab functions to avoid libselinux conflict.
+	* Removed original code from checkpolicy, which now uses libsepol.
+	* Code cleanup:  kill legacy references to kernel types/functions.
+
+0.1 2004-08-06
+	* Moved checkpolicy core logic into a library.
+	* Exported sepol_genbools() for load_policy.
diff --git a/libsepol/Makefile b/libsepol/Makefile
new file mode 100644
index 0000000..5b5d03e
--- /dev/null
+++ b/libsepol/Makefile
@@ -0,0 +1,30 @@
+DISABLE_CIL ?= n
+
+export DISABLE_CIL
+
+all: 
+	$(MAKE) -C src 
+	$(MAKE) -C utils
+
+install: 
+	$(MAKE) -C include install
+	$(MAKE) -C src install
+	$(MAKE) -C utils install
+	$(MAKE) -C man install
+
+relabel:
+	$(MAKE) -C src relabel
+
+clean:
+	$(MAKE) -C src clean
+	$(MAKE) -C utils clean
+	$(MAKE) -C tests clean
+
+indent:
+	$(MAKE) -C src $@
+	$(MAKE) -C include $@
+	$(MAKE) -C utils $@
+
+test:
+	$(MAKE) -C tests test
+
diff --git a/libsepol/VERSION b/libsepol/VERSION
new file mode 100644
index 0000000..95e3ba8
--- /dev/null
+++ b/libsepol/VERSION
@@ -0,0 +1 @@
+2.5
diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h
new file mode 100644
index 0000000..e4b10c5
--- /dev/null
+++ b/libsepol/cil/include/cil/cil.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_H_
+#define CIL_H_
+
+#include <sepol/policydb/policydb.h>
+
+struct cil_db;
+typedef struct cil_db cil_db_t;
+
+extern void cil_db_init(cil_db_t **db);
+extern void cil_db_destroy(cil_db_t **db);
+
+extern int cil_add_file(cil_db_t *db, char *name, char *data, size_t size);
+
+extern int cil_compile(cil_db_t *db);
+extern int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db);
+extern int cil_userprefixes_to_string(cil_db_t *db, char **out, size_t *size);
+extern int cil_selinuxusers_to_string(cil_db_t *db, char **out, size_t *size);
+extern int cil_filecons_to_string(cil_db_t *db, char **out, size_t *size);
+extern void cil_set_disable_dontaudit(cil_db_t *db, int disable_dontaudit);
+extern void cil_set_disable_neverallow(cil_db_t *db, int disable_neverallow);
+extern void cil_set_preserve_tunables(cil_db_t *db, int preserve_tunables);
+extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown);
+extern void cil_set_mls(cil_db_t *db, int mls);
+extern void cil_set_target_platform(cil_db_t *db, int target_platform);
+extern void cil_set_policy_version(cil_db_t *db, int policy_version);
+
+enum cil_log_level {
+	CIL_ERR = 1,
+	CIL_WARN,
+	CIL_INFO
+};
+extern void cil_set_log_level(enum cil_log_level lvl);
+extern void cil_set_log_handler(void (*handler)(int lvl, char *msg));
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 2, 3)))
+#endif
+extern void cil_log(enum cil_log_level lvl, const char *msg, ...);
+
+extern void cil_set_malloc_error_handler(void (*handler)(void));
+
+#endif
diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
new file mode 100644
index 0000000..929ab19
--- /dev/null
+++ b/libsepol/cil/src/cil.c
@@ -0,0 +1,2570 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/symtab.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+#include "cil_build_ast.h"
+
+#include "cil_parser.h"
+#include "cil_build_ast.h"
+#include "cil_resolve_ast.h"
+#include "cil_fqn.h"
+#include "cil_post.h"
+#include "cil_binary.h"
+#include "cil_policy.h"
+#include "cil_strpool.h"
+#include "dso.h"
+
+#ifndef DISABLE_SYMVER
+asm(".symver cil_build_policydb_pdb,        cil_build_policydb@");
+asm(".symver cil_build_policydb_create_pdb, cil_build_policydb@@LIBSEPOL_1.1");
+
+asm(".symver cil_compile_pdb,   cil_compile@");
+asm(".symver cil_compile_nopdb, cil_compile@@LIBSEPOL_1.1");
+
+asm(".symver cil_userprefixes_to_string_pdb,   cil_userprefixes_to_string@");
+asm(".symver cil_userprefixes_to_string_nopdb, cil_userprefixes_to_string@@LIBSEPOL_1.1");
+
+asm(".symver cil_selinuxusers_to_string_pdb,   cil_selinuxusers_to_string@");
+asm(".symver cil_selinuxusers_to_string_nopdb, cil_selinuxusers_to_string@@LIBSEPOL_1.1");
+
+asm(".symver cil_filecons_to_string_pdb,   cil_filecons_to_string@");
+asm(".symver cil_filecons_to_string_nopdb, cil_filecons_to_string@@LIBSEPOL_1.1");
+#endif
+
+int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = {
+	{64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+	{64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+};
+
+static void cil_init_keys(void)
+{
+	/* Initialize CIL Keys into strpool */
+	CIL_KEY_CONS_T1 = cil_strpool_add("t1");
+	CIL_KEY_CONS_T2 = cil_strpool_add("t2");
+	CIL_KEY_CONS_T3 = cil_strpool_add("t3");
+	CIL_KEY_CONS_R1 = cil_strpool_add("r1");
+	CIL_KEY_CONS_R2 = cil_strpool_add("r2");
+	CIL_KEY_CONS_R3 = cil_strpool_add("r3");
+	CIL_KEY_CONS_U1 = cil_strpool_add("u1");
+	CIL_KEY_CONS_U2 = cil_strpool_add("u2");
+	CIL_KEY_CONS_U3 = cil_strpool_add("u3");
+	CIL_KEY_CONS_L1 = cil_strpool_add("l1");
+	CIL_KEY_CONS_L2 = cil_strpool_add("l2");
+	CIL_KEY_CONS_H1 = cil_strpool_add("h1");
+	CIL_KEY_CONS_H2 = cil_strpool_add("h2");
+	CIL_KEY_AND = cil_strpool_add("and");
+	CIL_KEY_OR = cil_strpool_add("or");
+	CIL_KEY_NOT = cil_strpool_add("not");
+	CIL_KEY_EQ = cil_strpool_add("eq");
+	CIL_KEY_NEQ = cil_strpool_add("neq");
+	CIL_KEY_CONS_DOM = cil_strpool_add("dom");
+	CIL_KEY_CONS_DOMBY = cil_strpool_add("domby");
+	CIL_KEY_CONS_INCOMP = cil_strpool_add("incomp");
+	CIL_KEY_CONDTRUE = cil_strpool_add("true");
+	CIL_KEY_CONDFALSE = cil_strpool_add("false");
+	CIL_KEY_SELF = cil_strpool_add("self");
+	CIL_KEY_OBJECT_R = cil_strpool_add("object_r");
+	CIL_KEY_STAR = cil_strpool_add("*");
+	CIL_KEY_UDP = cil_strpool_add("udp");
+	CIL_KEY_TCP = cil_strpool_add("tcp");
+	CIL_KEY_DCCP = cil_strpool_add("dccp");
+	CIL_KEY_AUDITALLOW = cil_strpool_add("auditallow");
+	CIL_KEY_TUNABLEIF = cil_strpool_add("tunableif");
+	CIL_KEY_ALLOW = cil_strpool_add("allow");
+	CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit");
+	CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition");
+	CIL_KEY_TYPECHANGE = cil_strpool_add("typechange");
+	CIL_KEY_CALL = cil_strpool_add("call");
+	CIL_KEY_TUNABLE = cil_strpool_add("tunable");
+	CIL_KEY_XOR = cil_strpool_add("xor");
+	CIL_KEY_ALL = cil_strpool_add("all");
+	CIL_KEY_RANGE = cil_strpool_add("range");
+	CIL_KEY_TYPE = cil_strpool_add("type");
+	CIL_KEY_ROLE = cil_strpool_add("role");
+	CIL_KEY_USER = cil_strpool_add("user");
+	CIL_KEY_USERATTRIBUTE = cil_strpool_add("userattribute");
+	CIL_KEY_USERATTRIBUTESET = cil_strpool_add("userattributeset");
+	CIL_KEY_SENSITIVITY = cil_strpool_add("sensitivity");
+	CIL_KEY_CATEGORY = cil_strpool_add("category");
+	CIL_KEY_CATSET = cil_strpool_add("categoryset");
+	CIL_KEY_LEVEL = cil_strpool_add("level");
+	CIL_KEY_LEVELRANGE = cil_strpool_add("levelrange");
+	CIL_KEY_CLASS = cil_strpool_add("class");
+	CIL_KEY_IPADDR = cil_strpool_add("ipaddr");
+	CIL_KEY_MAP_CLASS = cil_strpool_add("classmap");
+	CIL_KEY_CLASSPERMISSION = cil_strpool_add("classpermission");
+	CIL_KEY_BOOL = cil_strpool_add("boolean");
+	CIL_KEY_STRING = cil_strpool_add("string");
+	CIL_KEY_NAME = cil_strpool_add("name");
+	CIL_KEY_HANDLEUNKNOWN = cil_strpool_add("handleunknown");
+	CIL_KEY_HANDLEUNKNOWN_ALLOW = cil_strpool_add("allow");
+	CIL_KEY_HANDLEUNKNOWN_DENY = cil_strpool_add("deny");
+	CIL_KEY_HANDLEUNKNOWN_REJECT = cil_strpool_add("reject");
+	CIL_KEY_BLOCKINHERIT = cil_strpool_add("blockinherit");
+	CIL_KEY_BLOCKABSTRACT = cil_strpool_add("blockabstract");
+	CIL_KEY_CLASSORDER = cil_strpool_add("classorder");
+	CIL_KEY_CLASSMAPPING = cil_strpool_add("classmapping");
+	CIL_KEY_CLASSPERMISSIONSET = cil_strpool_add("classpermissionset");
+	CIL_KEY_COMMON = cil_strpool_add("common");
+	CIL_KEY_CLASSCOMMON = cil_strpool_add("classcommon");
+	CIL_KEY_SID = cil_strpool_add("sid");
+	CIL_KEY_SIDCONTEXT = cil_strpool_add("sidcontext");
+	CIL_KEY_SIDORDER = cil_strpool_add("sidorder");
+	CIL_KEY_USERLEVEL = cil_strpool_add("userlevel");
+	CIL_KEY_USERRANGE = cil_strpool_add("userrange");
+	CIL_KEY_USERBOUNDS = cil_strpool_add("userbounds");
+	CIL_KEY_USERPREFIX = cil_strpool_add("userprefix");
+	CIL_KEY_SELINUXUSER = cil_strpool_add("selinuxuser");
+	CIL_KEY_SELINUXUSERDEFAULT = cil_strpool_add("selinuxuserdefault");
+	CIL_KEY_TYPEATTRIBUTE = cil_strpool_add("typeattribute");
+	CIL_KEY_TYPEATTRIBUTESET = cil_strpool_add("typeattributeset");
+	CIL_KEY_TYPEALIAS = cil_strpool_add("typealias");
+	CIL_KEY_TYPEALIASACTUAL = cil_strpool_add("typealiasactual");
+	CIL_KEY_TYPEBOUNDS = cil_strpool_add("typebounds");
+	CIL_KEY_TYPEPERMISSIVE = cil_strpool_add("typepermissive");
+	CIL_KEY_RANGETRANSITION = cil_strpool_add("rangetransition");
+	CIL_KEY_USERROLE = cil_strpool_add("userrole");
+	CIL_KEY_ROLETYPE = cil_strpool_add("roletype");
+	CIL_KEY_ROLETRANSITION = cil_strpool_add("roletransition");
+	CIL_KEY_ROLEALLOW = cil_strpool_add("roleallow");
+	CIL_KEY_ROLEATTRIBUTE = cil_strpool_add("roleattribute");
+	CIL_KEY_ROLEATTRIBUTESET = cil_strpool_add("roleattributeset");
+	CIL_KEY_ROLEBOUNDS = cil_strpool_add("rolebounds");
+	CIL_KEY_BOOLEANIF = cil_strpool_add("booleanif");
+	CIL_KEY_NEVERALLOW = cil_strpool_add("neverallow");
+	CIL_KEY_TYPEMEMBER = cil_strpool_add("typemember");
+	CIL_KEY_SENSALIAS = cil_strpool_add("sensitivityalias");
+	CIL_KEY_SENSALIASACTUAL = cil_strpool_add("sensitivityaliasactual");
+	CIL_KEY_CATALIAS = cil_strpool_add("categoryalias");
+	CIL_KEY_CATALIASACTUAL = cil_strpool_add("categoryaliasactual");
+	CIL_KEY_CATORDER = cil_strpool_add("categoryorder");
+	CIL_KEY_SENSITIVITYORDER = cil_strpool_add("sensitivityorder");
+	CIL_KEY_SENSCAT = cil_strpool_add("sensitivitycategory");
+	CIL_KEY_CONSTRAIN = cil_strpool_add("constrain");
+	CIL_KEY_MLSCONSTRAIN = cil_strpool_add("mlsconstrain");
+	CIL_KEY_VALIDATETRANS = cil_strpool_add("validatetrans");
+	CIL_KEY_MLSVALIDATETRANS = cil_strpool_add("mlsvalidatetrans");
+	CIL_KEY_CONTEXT = cil_strpool_add("context");
+	CIL_KEY_FILECON = cil_strpool_add("filecon");
+	CIL_KEY_PORTCON = cil_strpool_add("portcon");
+	CIL_KEY_NODECON = cil_strpool_add("nodecon");
+	CIL_KEY_GENFSCON = cil_strpool_add("genfscon");
+	CIL_KEY_NETIFCON = cil_strpool_add("netifcon");
+	CIL_KEY_PIRQCON = cil_strpool_add("pirqcon");
+	CIL_KEY_IOMEMCON = cil_strpool_add("iomemcon");
+	CIL_KEY_IOPORTCON = cil_strpool_add("ioportcon");
+	CIL_KEY_PCIDEVICECON = cil_strpool_add("pcidevicecon");
+	CIL_KEY_DEVICETREECON = cil_strpool_add("devicetreecon");
+	CIL_KEY_FSUSE = cil_strpool_add("fsuse");
+	CIL_KEY_POLICYCAP = cil_strpool_add("policycap");
+	CIL_KEY_OPTIONAL = cil_strpool_add("optional");
+	CIL_KEY_DEFAULTUSER = cil_strpool_add("defaultuser");
+	CIL_KEY_DEFAULTROLE = cil_strpool_add("defaultrole");
+	CIL_KEY_DEFAULTTYPE = cil_strpool_add("defaulttype");
+	CIL_KEY_MACRO = cil_strpool_add("macro");
+	CIL_KEY_IN = cil_strpool_add("in");
+	CIL_KEY_MLS = cil_strpool_add("mls");
+	CIL_KEY_DEFAULTRANGE = cil_strpool_add("defaultrange");
+	CIL_KEY_GLOB = cil_strpool_add("*");
+	CIL_KEY_FILE = cil_strpool_add("file");
+	CIL_KEY_DIR = cil_strpool_add("dir");
+	CIL_KEY_CHAR = cil_strpool_add("char");
+	CIL_KEY_BLOCK = cil_strpool_add("block");
+	CIL_KEY_SOCKET = cil_strpool_add("socket");
+	CIL_KEY_PIPE = cil_strpool_add("pipe");
+	CIL_KEY_SYMLINK = cil_strpool_add("symlink");
+	CIL_KEY_ANY = cil_strpool_add("any");
+	CIL_KEY_XATTR = cil_strpool_add("xattr");
+	CIL_KEY_TASK = cil_strpool_add("task");
+	CIL_KEY_TRANS = cil_strpool_add("trans");
+	CIL_KEY_SOURCE = cil_strpool_add("source");
+	CIL_KEY_TARGET = cil_strpool_add("target");
+	CIL_KEY_LOW = cil_strpool_add("low");
+	CIL_KEY_HIGH = cil_strpool_add("high");
+	CIL_KEY_LOW_HIGH = cil_strpool_add("low-high");
+	CIL_KEY_ROOT = cil_strpool_add("<root>");
+	CIL_KEY_NODE = cil_strpool_add("<node>");
+	CIL_KEY_PERM = cil_strpool_add("perm");
+	CIL_KEY_ALLOWX = cil_strpool_add("allowx");
+	CIL_KEY_AUDITALLOWX = cil_strpool_add("auditallowx");
+	CIL_KEY_DONTAUDITX = cil_strpool_add("dontauditx");
+	CIL_KEY_NEVERALLOWX = cil_strpool_add("neverallowx");
+	CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx");
+	CIL_KEY_IOCTL = cil_strpool_add("ioctl");
+	CIL_KEY_UNORDERED = cil_strpool_add("unordered");
+	CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>");
+	CIL_KEY_SRC_CIL = cil_strpool_add("<src_cil>");
+	CIL_KEY_SRC_HLL = cil_strpool_add("<src_hll>");
+}
+
+void cil_db_init(struct cil_db **db)
+{
+	*db = cil_malloc(sizeof(**db));
+
+	cil_strpool_init();
+	cil_init_keys();
+
+	cil_tree_init(&(*db)->parse);
+	cil_tree_init(&(*db)->ast);
+	cil_root_init((struct cil_root **)&(*db)->ast->root->data);
+	(*db)->sidorder = NULL;
+	(*db)->classorder = NULL;
+	(*db)->catorder = NULL;
+	(*db)->sensitivityorder = NULL;
+	cil_sort_init(&(*db)->netifcon);
+	cil_sort_init(&(*db)->genfscon);
+	cil_sort_init(&(*db)->filecon);
+	cil_sort_init(&(*db)->nodecon);
+	cil_sort_init(&(*db)->portcon);
+	cil_sort_init(&(*db)->pirqcon);
+	cil_sort_init(&(*db)->iomemcon);
+	cil_sort_init(&(*db)->ioportcon);
+	cil_sort_init(&(*db)->pcidevicecon);
+	cil_sort_init(&(*db)->devicetreecon);
+	cil_sort_init(&(*db)->fsuse);
+	cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM);
+	cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM);
+	cil_list_init(&(*db)->names, CIL_LIST_ITEM);
+
+	cil_type_init(&(*db)->selftype);
+	(*db)->selftype->datum.name = CIL_KEY_SELF;
+	(*db)->selftype->datum.fqn = CIL_KEY_SELF;
+	(*db)->num_types_and_attrs = 0;
+	(*db)->num_classes = 0;
+	(*db)->num_types = 0;
+	(*db)->num_roles = 0;
+	(*db)->num_users = 0;
+	(*db)->num_cats = 0;
+	(*db)->val_to_type = NULL;
+	(*db)->val_to_role = NULL;
+	(*db)->val_to_user = NULL;
+
+	(*db)->disable_dontaudit = CIL_FALSE;
+	(*db)->disable_neverallow = CIL_FALSE;
+	(*db)->preserve_tunables = CIL_FALSE;
+	(*db)->handle_unknown = -1;
+	(*db)->mls = -1;
+	(*db)->target_platform = SEPOL_TARGET_SELINUX;
+	(*db)->policy_version = POLICYDB_VERSION_MAX;
+}
+
+void cil_db_destroy(struct cil_db **db)
+{
+	if (db == NULL || *db == NULL) {
+		return;
+	}
+
+	cil_tree_destroy(&(*db)->parse);
+	cil_tree_destroy(&(*db)->ast);
+	cil_list_destroy(&(*db)->sidorder, CIL_FALSE);
+	cil_list_destroy(&(*db)->classorder, CIL_FALSE);
+	cil_list_destroy(&(*db)->catorder, CIL_FALSE);
+	cil_list_destroy(&(*db)->sensitivityorder, CIL_FALSE);
+	cil_sort_destroy(&(*db)->netifcon);
+	cil_sort_destroy(&(*db)->genfscon);
+	cil_sort_destroy(&(*db)->filecon);
+	cil_sort_destroy(&(*db)->nodecon);
+	cil_sort_destroy(&(*db)->portcon);
+	cil_sort_destroy(&(*db)->pirqcon);
+	cil_sort_destroy(&(*db)->iomemcon);
+	cil_sort_destroy(&(*db)->ioportcon);
+	cil_sort_destroy(&(*db)->pcidevicecon);
+	cil_sort_destroy(&(*db)->devicetreecon);
+	cil_sort_destroy(&(*db)->fsuse);
+	cil_list_destroy(&(*db)->userprefixes, CIL_FALSE);
+	cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE);
+	cil_list_destroy(&(*db)->names, CIL_TRUE);
+
+	cil_destroy_type((*db)->selftype);
+
+	cil_strpool_destroy();
+	free((*db)->val_to_type);
+	free((*db)->val_to_role);
+	free((*db)->val_to_user);
+
+	free(*db);
+	*db = NULL;	
+}
+
+void cil_root_init(struct cil_root **root)
+{
+	struct cil_root *r = cil_malloc(sizeof(*r));
+	cil_symtab_array_init(r->symtab, cil_sym_sizes[CIL_SYM_ARRAY_ROOT]);
+
+	*root = r;
+}
+
+void cil_root_destroy(struct cil_root *root)
+{
+	if (root == NULL) {
+		return;
+	}
+	cil_symtab_array_destroy(root->symtab);
+	free(root);
+}
+
+int cil_add_file(cil_db_t *db, char *name, char *data, size_t size)
+{
+	char *buffer = NULL;
+	int rc;
+
+	cil_log(CIL_INFO, "Parsing %s\n", name);
+
+	buffer = cil_malloc(size + 2);
+	memcpy(buffer, data, size);
+	memset(buffer + size, 0, 2);
+
+	rc = cil_parser(name, buffer, size + 2, &db->parse);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to parse %s\n", name);
+		goto exit;
+	}
+
+	free(buffer);
+	buffer = NULL;
+
+	rc = SEPOL_OK;
+
+exit:
+	free(buffer);
+
+	return rc;
+}
+
+#ifdef DISABLE_SYMVER
+int cil_compile(struct cil_db *db)
+#else
+int cil_compile_nopdb(struct cil_db *db)
+#endif
+{
+	int rc = SEPOL_ERR;
+
+	if (db == NULL) {
+		goto exit;
+	}
+
+	cil_log(CIL_INFO, "Building AST from Parse Tree\n");
+	rc = cil_build_ast(db, db->parse->root, db->ast->root);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to build ast\n");
+		goto exit;
+	}
+
+	cil_log(CIL_INFO, "Destroying Parse Tree\n");
+	cil_tree_destroy(&db->parse);
+
+	cil_log(CIL_INFO, "Resolving AST\n");
+	rc = cil_resolve_ast(db, db->ast->root);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to resolve ast\n");
+		goto exit;
+	}
+
+	cil_log(CIL_INFO, "Qualifying Names\n");
+	rc = cil_fqn_qualify(db->ast->root);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to qualify names\n");
+		goto exit;
+	}
+
+	cil_log(CIL_INFO, "Compile post process\n");
+	rc = cil_post_process(db);
+	if (rc != SEPOL_OK ) {
+		cil_log(CIL_INFO, "Post process failed\n");
+		goto exit;
+	}
+
+exit:
+
+	return rc;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_compile_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db)
+{
+	return cil_compile_nopdb(db);
+}
+
+int cil_build_policydb_pdb(cil_db_t *db, sepol_policydb_t *sepol_db)
+{
+	int rc;
+
+	cil_log(CIL_INFO, "Building policy binary\n");
+	rc = cil_binary_create_allocated_pdb(db, sepol_db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to generate binary\n");
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+#endif
+
+#ifdef DISABLE_SYMVER
+int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db)
+#else
+int cil_build_policydb_create_pdb(cil_db_t *db, sepol_policydb_t **sepol_db)
+#endif
+{
+	int rc;
+
+	cil_log(CIL_INFO, "Building policy binary\n");
+	rc = cil_binary_create(db, sepol_db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to generate binary\n");
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+void cil_destroy_data(void **data, enum cil_flavor flavor)
+{
+	if (*data == NULL) {
+		return;
+	}
+
+	switch(flavor) {
+	case CIL_NONE:
+		break;
+	case CIL_ROOT:
+		cil_root_destroy(*data);
+		break;
+	case CIL_NODE:
+		break;
+	case CIL_STRING:
+		break;
+	case CIL_DATUM:
+		break;
+	case CIL_LIST:
+		cil_list_destroy(*data, CIL_FALSE);
+		break;
+	case CIL_LIST_ITEM:
+		break;
+	case CIL_PARAM:
+		cil_destroy_param(*data);
+		break;
+	case CIL_ARGS:
+		cil_destroy_args(*data);
+		break;
+	case CIL_BLOCK:
+		cil_destroy_block(*data);
+		break;
+	case CIL_BLOCKINHERIT:
+		cil_destroy_blockinherit(*data);
+		break;
+	case CIL_BLOCKABSTRACT:
+		cil_destroy_blockabstract(*data);
+		break;
+	case CIL_IN:
+		cil_destroy_in(*data);
+		break;
+	case CIL_MACRO:
+		cil_destroy_macro(*data);
+		break;
+	case CIL_CALL:
+		cil_destroy_call(*data);
+		break;
+	case CIL_OPTIONAL:
+		cil_destroy_optional(*data);
+		break;
+	case CIL_BOOL:
+		cil_destroy_bool(*data);
+		break;
+	case CIL_BOOLEANIF:
+		cil_destroy_boolif(*data);
+		break;
+	case CIL_TUNABLE:
+		cil_destroy_tunable(*data);
+		break;
+	case CIL_TUNABLEIF:
+		cil_destroy_tunif(*data);
+		break;
+	case CIL_CONDBLOCK:
+		cil_destroy_condblock(*data);
+		break;
+	case CIL_CONDTRUE:
+		break;
+	case CIL_CONDFALSE:
+		break;
+	case CIL_PERM:
+	case CIL_MAP_PERM:
+		cil_destroy_perm(*data);
+		break;
+	case CIL_COMMON:
+	case CIL_CLASS:
+	case CIL_MAP_CLASS:
+		cil_destroy_class(*data);
+		break;
+	case CIL_CLASSORDER:
+		cil_destroy_classorder(*data);
+		break;
+	case CIL_CLASSPERMISSION:
+		cil_destroy_classpermission(*data);
+		break;
+	case CIL_CLASSCOMMON:
+		cil_destroy_classcommon(*data);
+		break;
+	case CIL_CLASSMAPPING:
+		cil_destroy_classmapping(*data);
+		break;
+	case CIL_CLASSPERMS:
+		cil_destroy_classperms(*data);
+		break;
+	case CIL_CLASSPERMS_SET:
+		cil_destroy_classperms_set(*data);
+		break;
+	case CIL_CLASSPERMISSIONSET:
+		cil_destroy_classpermissionset(*data);
+		break;
+	case CIL_USER:
+		cil_destroy_user(*data);
+		break;
+	case CIL_USERATTRIBUTE:
+		cil_destroy_userattribute(*data);
+		break;
+	case CIL_USERATTRIBUTESET:
+		cil_destroy_userattributeset(*data);
+		break;
+	case CIL_USERPREFIX:
+		cil_destroy_userprefix(*data);
+		break;
+	case CIL_USERROLE:
+		cil_destroy_userrole(*data);
+		break;
+	case CIL_USERLEVEL:
+		cil_destroy_userlevel(*data);
+		break;
+	case CIL_USERRANGE:
+		cil_destroy_userrange(*data);
+		break;
+	case CIL_USERBOUNDS:
+		cil_destroy_bounds(*data);
+		break;
+	case CIL_SELINUXUSER:
+	case CIL_SELINUXUSERDEFAULT:
+		cil_destroy_selinuxuser(*data);
+		break;
+	case CIL_ROLE:
+		cil_destroy_role(*data);
+		break;
+	case CIL_ROLEATTRIBUTE:
+		cil_destroy_roleattribute(*data);
+		break;
+	case CIL_ROLEATTRIBUTESET:
+		cil_destroy_roleattributeset(*data);
+		break;
+	case CIL_ROLETYPE:
+		cil_destroy_roletype(*data);
+		break;
+	case CIL_ROLEBOUNDS:
+		cil_destroy_bounds(*data);
+		break;
+	case CIL_TYPE:
+		cil_destroy_type(*data);
+		break;
+	case CIL_TYPEATTRIBUTE:
+		cil_destroy_typeattribute(*data);
+		break;
+	case CIL_TYPEALIAS:
+		cil_destroy_alias(*data);
+		break;
+	case CIL_TYPEATTRIBUTESET:
+		cil_destroy_typeattributeset(*data);
+		break;
+	case CIL_TYPEALIASACTUAL:
+		cil_destroy_aliasactual(*data);
+		break;
+	case CIL_TYPEBOUNDS:
+		cil_destroy_bounds(*data);
+		break;
+	case CIL_TYPEPERMISSIVE:
+		cil_destroy_typepermissive(*data);
+		break;
+	case CIL_SENS:
+		cil_destroy_sensitivity(*data);
+		break;
+	case CIL_SENSALIAS:
+		cil_destroy_alias(*data);
+		break;
+	case CIL_SENSALIASACTUAL:
+		cil_destroy_aliasactual(*data);
+		break;
+	case CIL_SENSITIVITYORDER:
+		cil_destroy_sensitivityorder(*data);
+		break;
+	case CIL_SENSCAT:
+		cil_destroy_senscat(*data);
+		break;
+	case CIL_CAT:
+		cil_destroy_category(*data);
+		break;
+	case CIL_CATSET:
+		cil_destroy_catset(*data);
+		break;
+	case CIL_CATALIAS:
+		cil_destroy_alias(*data);
+		break;
+	case CIL_CATALIASACTUAL:
+		cil_destroy_aliasactual(*data);
+		break;
+	case CIL_CATORDER:
+		cil_destroy_catorder(*data);
+		break;
+	case CIL_LEVEL:
+		cil_destroy_level(*data);
+		break;
+	case CIL_LEVELRANGE:
+		cil_destroy_levelrange(*data);
+		break;
+	case CIL_SID:
+		cil_destroy_sid(*data);
+		break;
+	case CIL_SIDORDER:
+		cil_destroy_sidorder(*data);
+		break;
+	case CIL_NAME:
+		cil_destroy_name(*data);
+		break;
+	case CIL_ROLEALLOW:
+		cil_destroy_roleallow(*data);
+		break;
+	case CIL_AVRULE:
+	case CIL_AVRULEX:
+		cil_destroy_avrule(*data);
+		break;
+	case CIL_PERMISSIONX:
+		cil_destroy_permissionx(*data);
+		break;
+	case CIL_ROLETRANSITION:
+		cil_destroy_roletransition(*data);
+		break;
+	case CIL_TYPE_RULE:
+		cil_destroy_type_rule(*data);
+		break;
+	case CIL_NAMETYPETRANSITION:
+		cil_destroy_typetransition(*data);
+		break;
+	case CIL_RANGETRANSITION:
+		cil_destroy_rangetransition(*data);
+		break;
+	case CIL_CONSTRAIN:
+		cil_destroy_constrain(*data);
+		break;
+	case CIL_MLSCONSTRAIN:
+		cil_destroy_constrain(*data);
+		break;
+	case CIL_VALIDATETRANS:
+	case CIL_MLSVALIDATETRANS:
+		cil_destroy_validatetrans(*data);
+		break;
+	case CIL_CONTEXT:
+		cil_destroy_context(*data);
+		break;
+	case CIL_IPADDR:
+		cil_destroy_ipaddr(*data);
+		break;
+	case CIL_SIDCONTEXT:
+		cil_destroy_sidcontext(*data);
+		break;
+	case CIL_FSUSE:
+		cil_destroy_fsuse(*data);
+		break;
+	case CIL_FILECON:
+		cil_destroy_filecon(*data);
+		break;
+	case CIL_PORTCON:
+		cil_destroy_portcon(*data);
+		break;
+	case CIL_NODECON:
+		cil_destroy_nodecon(*data);
+		break;
+	case CIL_GENFSCON:
+		cil_destroy_genfscon(*data);
+		break;
+	case CIL_NETIFCON:
+		cil_destroy_netifcon(*data);
+		break;
+	case CIL_PIRQCON:
+		cil_destroy_pirqcon(*data);
+		break;
+	case CIL_IOMEMCON:
+		cil_destroy_iomemcon(*data);
+		break;
+	case CIL_IOPORTCON:
+		cil_destroy_ioportcon(*data);
+		break;
+	case CIL_PCIDEVICECON:
+		cil_destroy_pcidevicecon(*data);
+		break;
+	case CIL_DEVICETREECON:
+		cil_destroy_devicetreecon(*data);
+		break;
+	case CIL_POLICYCAP:
+		cil_destroy_policycap(*data);
+		break;
+	case CIL_DEFAULTUSER:
+	case CIL_DEFAULTROLE:
+	case CIL_DEFAULTTYPE:
+		cil_destroy_default(*data);
+		break;
+	case CIL_DEFAULTRANGE:
+		cil_destroy_defaultrange(*data);
+		break;
+	case CIL_HANDLEUNKNOWN:
+		cil_destroy_handleunknown(*data);
+		break;
+	case CIL_MLS:
+		cil_destroy_mls(*data);
+		break;
+	case CIL_SRC_INFO:
+		cil_destroy_src_info(*data);
+		break;
+	case CIL_OP:
+	case CIL_CONS_OPERAND:
+		break;
+	default:
+		cil_log(CIL_INFO, "Unknown data flavor: %d\n", flavor);
+		break;
+	}
+
+	*data = NULL;
+}
+
+int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_index)
+{
+	if (flavor < CIL_MIN_DECLARATIVE) {
+		return SEPOL_ERR;
+	}
+
+	switch(flavor) {
+	case CIL_BLOCK:
+		*sym_index = CIL_SYM_BLOCKS;
+		break;
+	case CIL_MACRO:
+		*sym_index = CIL_SYM_BLOCKS;
+		break;
+	case CIL_OPTIONAL:
+		*sym_index = CIL_SYM_BLOCKS;
+		break;
+	case CIL_BOOL:
+		*sym_index = CIL_SYM_BOOLS;
+		break;
+	case CIL_TUNABLE:
+		*sym_index = CIL_SYM_TUNABLES;
+		break;
+	case CIL_PERM:
+	case CIL_MAP_PERM:
+		*sym_index = CIL_SYM_PERMS;
+		break;
+	case CIL_COMMON:
+		*sym_index = CIL_SYM_COMMONS;
+		break;
+	case CIL_CLASS:
+	case CIL_MAP_CLASS:
+		*sym_index = CIL_SYM_CLASSES;
+		break;
+	case CIL_CLASSPERMISSION:
+	case CIL_CLASSPERMISSIONSET:
+		*sym_index = CIL_SYM_CLASSPERMSETS;
+		break;
+	case CIL_USER:
+	case CIL_USERATTRIBUTE:
+		*sym_index = CIL_SYM_USERS;
+		break;
+	case CIL_ROLE:
+	case CIL_ROLEATTRIBUTE:
+		*sym_index = CIL_SYM_ROLES;
+		break;
+	case CIL_TYPE:
+	case CIL_TYPEALIAS:
+	case CIL_TYPEATTRIBUTE:
+		*sym_index = CIL_SYM_TYPES;
+		break;
+	case CIL_SENS:
+	case CIL_SENSALIAS:
+		*sym_index = CIL_SYM_SENS;
+		break;
+	case CIL_CAT:
+	case CIL_CATSET:
+	case CIL_CATALIAS:
+		*sym_index = CIL_SYM_CATS;
+		break;
+	case CIL_LEVEL:
+		*sym_index = CIL_SYM_LEVELS;
+		break;
+	case CIL_LEVELRANGE:
+		*sym_index = CIL_SYM_LEVELRANGES;
+		break;
+	case CIL_SID:
+		*sym_index = CIL_SYM_SIDS;
+		break;
+	case CIL_NAME:
+		*sym_index = CIL_SYM_NAMES;
+		break;
+	case CIL_CONTEXT:
+		*sym_index = CIL_SYM_CONTEXTS;
+		break;
+	case CIL_IPADDR:
+		*sym_index = CIL_SYM_IPADDRS;
+		break;
+	case CIL_POLICYCAP:
+		*sym_index = CIL_SYM_POLICYCAPS;
+		break;
+	case CIL_PERMISSIONX:
+		*sym_index = CIL_SYM_PERMX;
+		break;
+	default:
+		*sym_index = CIL_SYM_UNKNOWN;
+		cil_log(CIL_INFO, "Failed to find flavor: %d\n", flavor);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+const char * cil_node_to_string(struct cil_tree_node *node)
+{
+	switch (node->flavor) {
+	case CIL_NONE:
+		return "<none>";
+	case CIL_ROOT:
+		return CIL_KEY_ROOT;
+	case CIL_NODE:
+		return CIL_KEY_NODE;
+	case CIL_STRING:
+		return "string";
+	case CIL_DATUM:
+		return "<datum>";
+	case CIL_LIST:
+		return "<list>";
+	case CIL_LIST_ITEM:
+		return "<list_item>";
+	case CIL_PARAM:
+		return "<param>";
+	case CIL_ARGS:
+		return "<args>";
+	case CIL_BLOCK:
+		return CIL_KEY_BLOCK;
+	case CIL_BLOCKINHERIT:
+		return CIL_KEY_BLOCKINHERIT;
+	case CIL_BLOCKABSTRACT:
+		return CIL_KEY_BLOCKABSTRACT;
+	case CIL_IN:
+		return CIL_KEY_IN;
+	case CIL_MACRO:
+		return CIL_KEY_MACRO;
+	case CIL_CALL:
+		return CIL_KEY_CALL;
+	case CIL_OPTIONAL:
+		return CIL_KEY_OPTIONAL;
+	case CIL_BOOL:
+		return CIL_KEY_BOOL;
+	case CIL_BOOLEANIF:
+		return CIL_KEY_BOOLEANIF;
+	case CIL_TUNABLE:
+		return CIL_KEY_TUNABLE;
+	case CIL_TUNABLEIF:
+		return CIL_KEY_TUNABLEIF;
+	case CIL_CONDBLOCK:
+		switch (((struct cil_condblock*)node->data)->flavor) {
+		case CIL_CONDTRUE:
+			return CIL_KEY_CONDTRUE;
+		case CIL_CONDFALSE:
+			return CIL_KEY_CONDFALSE;
+		default:
+			break;
+		}
+		break;
+	case CIL_CONDTRUE:
+		return CIL_KEY_CONDTRUE;
+	case CIL_CONDFALSE:
+		return CIL_KEY_CONDFALSE;
+	case CIL_PERM:
+		return CIL_KEY_PERM;
+	case CIL_COMMON:
+		return CIL_KEY_COMMON;
+	case CIL_CLASS:
+		return CIL_KEY_CLASS;
+	case CIL_CLASSORDER:
+		return CIL_KEY_CLASSORDER;
+	case CIL_MAP_CLASS:
+		return CIL_KEY_MAP_CLASS;
+	case CIL_CLASSPERMISSION:
+		return CIL_KEY_CLASSPERMISSION;
+	case CIL_CLASSCOMMON:
+		return CIL_KEY_CLASSCOMMON;
+	case CIL_CLASSMAPPING:
+		return CIL_KEY_CLASSMAPPING;
+	case CIL_CLASSPERMISSIONSET:
+		return CIL_KEY_CLASSPERMISSIONSET;
+	case CIL_USER:
+		return CIL_KEY_USER;
+	case CIL_USERATTRIBUTE:
+		return CIL_KEY_USERATTRIBUTE;
+	case CIL_USERATTRIBUTESET:
+		return CIL_KEY_USERATTRIBUTESET;
+	case CIL_USERPREFIX:
+		return CIL_KEY_USERPREFIX;
+	case CIL_USERROLE:
+		return CIL_KEY_USERROLE;
+	case CIL_USERLEVEL:
+		return CIL_KEY_USERLEVEL;
+	case CIL_USERRANGE:
+		return CIL_KEY_USERRANGE;
+	case CIL_USERBOUNDS:
+		return CIL_KEY_USERBOUNDS;
+	case CIL_SELINUXUSER:
+		return CIL_KEY_SELINUXUSER;
+	case CIL_SELINUXUSERDEFAULT:
+		return CIL_KEY_SELINUXUSERDEFAULT;
+	case CIL_ROLE:
+		return CIL_KEY_ROLE;
+	case CIL_ROLEATTRIBUTE:
+		return CIL_KEY_ROLEATTRIBUTE;
+	case CIL_ROLEATTRIBUTESET:
+		return CIL_KEY_ROLEATTRIBUTESET;
+	case CIL_ROLETYPE:
+		return CIL_KEY_ROLETYPE;
+	case CIL_ROLEBOUNDS:
+		return CIL_KEY_ROLEBOUNDS;
+	case CIL_TYPE:
+		return CIL_KEY_TYPE;
+	case CIL_TYPEATTRIBUTE:
+		return CIL_KEY_TYPEATTRIBUTE;
+	case CIL_TYPEALIAS:
+		return CIL_KEY_TYPEALIAS;
+	case CIL_TYPEATTRIBUTESET:
+		return CIL_KEY_TYPEATTRIBUTESET;
+	case CIL_TYPEALIASACTUAL:
+		return CIL_KEY_TYPEALIASACTUAL;
+	case CIL_TYPEBOUNDS:
+		return CIL_KEY_TYPEBOUNDS;
+	case CIL_TYPEPERMISSIVE:
+		return CIL_KEY_TYPEPERMISSIVE;
+	case CIL_SENS:
+		return CIL_KEY_SENSITIVITY;
+	case CIL_SENSALIAS:
+		return CIL_KEY_SENSALIAS;
+	case CIL_SENSALIASACTUAL:
+		return CIL_KEY_SENSALIASACTUAL;
+	case CIL_SENSITIVITYORDER:
+		return CIL_KEY_SENSITIVITYORDER;
+	case CIL_SENSCAT:
+		return CIL_KEY_SENSCAT;
+	case CIL_CAT:
+		return CIL_KEY_CATEGORY;
+	case CIL_CATSET:
+		return CIL_KEY_CATSET;
+	case CIL_CATALIAS:
+		return CIL_KEY_CATALIAS;
+	case CIL_CATALIASACTUAL:
+		return CIL_KEY_CATALIASACTUAL;
+	case CIL_CATORDER:
+		return CIL_KEY_CATORDER;
+	case CIL_LEVEL:
+		return CIL_KEY_LEVEL;
+	case CIL_LEVELRANGE:
+		return CIL_KEY_LEVELRANGE;
+	case CIL_SID:
+		return CIL_KEY_SID;
+	case CIL_SIDORDER:
+		return CIL_KEY_SIDORDER;
+	case CIL_NAME:
+		return CIL_KEY_NAME;
+	case CIL_ROLEALLOW:
+		return CIL_KEY_ROLEALLOW;
+	case CIL_AVRULE:
+		switch (((struct cil_avrule *)node->data)->rule_kind) {
+		case CIL_AVRULE_ALLOWED:
+			return CIL_KEY_ALLOW;
+		case CIL_AVRULE_AUDITALLOW:
+			return CIL_KEY_AUDITALLOW;
+		case CIL_AVRULE_DONTAUDIT:
+			return CIL_KEY_DONTAUDIT;
+		case CIL_AVRULE_NEVERALLOW:
+			return CIL_KEY_NEVERALLOW;
+		default:
+			break;
+		}
+		break;
+	case CIL_AVRULEX:
+		switch (((struct cil_avrule *)node->data)->rule_kind) {
+		case CIL_AVRULE_ALLOWED:
+			return CIL_KEY_ALLOWX;
+		case CIL_AVRULE_AUDITALLOW:
+			return CIL_KEY_AUDITALLOWX;
+		case CIL_AVRULE_DONTAUDIT:
+			return CIL_KEY_DONTAUDITX;
+		case CIL_AVRULE_NEVERALLOW:
+			return CIL_KEY_NEVERALLOWX;
+		default:
+			break;
+		}
+		break;
+	case CIL_PERMISSIONX:
+		return CIL_KEY_PERMISSIONX;
+	case CIL_ROLETRANSITION:
+		return CIL_KEY_ROLETRANSITION;
+	case CIL_TYPE_RULE:
+		switch (((struct cil_type_rule *)node->data)->rule_kind) {
+		case CIL_TYPE_TRANSITION:
+			return CIL_KEY_TYPETRANSITION;
+		case CIL_TYPE_MEMBER:
+			return CIL_KEY_TYPEMEMBER;
+		case CIL_TYPE_CHANGE:
+			return CIL_KEY_TYPECHANGE;
+		default:
+			break;
+		}
+		break;
+	case CIL_NAMETYPETRANSITION:
+		return CIL_KEY_TYPETRANSITION;
+	case CIL_RANGETRANSITION:
+		return CIL_KEY_RANGETRANSITION;
+	case CIL_CONSTRAIN:
+		return CIL_KEY_CONSTRAIN;
+	case CIL_MLSCONSTRAIN:
+		return CIL_KEY_MLSCONSTRAIN;
+	case CIL_VALIDATETRANS:
+		return CIL_KEY_VALIDATETRANS;
+	case CIL_MLSVALIDATETRANS:
+		return CIL_KEY_MLSVALIDATETRANS;
+	case CIL_CONTEXT:
+		return CIL_KEY_CONTEXT;
+	case CIL_IPADDR:
+		return CIL_KEY_IPADDR;
+	case CIL_SIDCONTEXT:
+		return CIL_KEY_SIDCONTEXT;
+	case CIL_FSUSE:
+		return CIL_KEY_FSUSE;
+	case CIL_FILECON:
+		return CIL_KEY_FILECON;
+	case CIL_PORTCON:
+		return CIL_KEY_PORTCON;
+	case CIL_NODECON:
+		return CIL_KEY_NODECON;
+	case CIL_GENFSCON:
+		return CIL_KEY_GENFSCON;
+	case CIL_NETIFCON:
+		return CIL_KEY_NETIFCON;
+	case CIL_PIRQCON:
+		return CIL_KEY_PIRQCON;
+	case CIL_IOMEMCON:
+		return CIL_KEY_IOMEMCON;
+	case CIL_IOPORTCON:
+		return CIL_KEY_IOPORTCON;
+	case CIL_PCIDEVICECON:
+		return CIL_KEY_PCIDEVICECON;
+	case CIL_DEVICETREECON:
+		return CIL_KEY_DEVICETREECON;
+	case CIL_POLICYCAP:
+		return CIL_KEY_POLICYCAP;
+	case CIL_DEFAULTUSER:
+		return CIL_KEY_DEFAULTUSER;
+	case CIL_DEFAULTROLE:
+		return CIL_KEY_DEFAULTROLE;
+	case CIL_DEFAULTTYPE:
+		return CIL_KEY_DEFAULTTYPE;
+	case CIL_DEFAULTRANGE:
+		return CIL_KEY_DEFAULTRANGE;
+	case CIL_HANDLEUNKNOWN:
+		return CIL_KEY_HANDLEUNKNOWN;
+	case CIL_MLS:
+		return CIL_KEY_MLS;
+	case CIL_SRC_INFO:
+		return CIL_KEY_SRC_INFO;
+	case CIL_ALL:
+		return CIL_KEY_ALL;
+	case CIL_RANGE:
+		return CIL_KEY_RANGE;
+	case CIL_AND:
+		return CIL_KEY_AND;
+	case CIL_OR:
+		return CIL_KEY_OR;
+	case CIL_XOR:
+		return CIL_KEY_XOR;
+	case CIL_NOT:
+		return CIL_KEY_NOT;
+	case CIL_EQ:
+		return CIL_KEY_EQ;
+	case CIL_NEQ:
+		return CIL_KEY_NEQ;
+	case CIL_CONS_DOM:
+		return CIL_KEY_CONS_DOM;
+	case CIL_CONS_DOMBY:
+		return CIL_KEY_CONS_DOMBY;
+	case CIL_CONS_INCOMP:
+		return CIL_KEY_CONS_INCOMP;
+	case CIL_CONS_U1:
+		return CIL_KEY_CONS_U1;
+	case CIL_CONS_U2:
+		return CIL_KEY_CONS_U2;
+	case CIL_CONS_U3:
+		return CIL_KEY_CONS_U3;
+	case CIL_CONS_T1:
+		return CIL_KEY_CONS_T1;
+	case CIL_CONS_T2:
+		return CIL_KEY_CONS_T2;
+	case CIL_CONS_T3:
+		return CIL_KEY_CONS_T3;
+	case CIL_CONS_R1:
+		return CIL_KEY_CONS_R1;
+	case CIL_CONS_R2:
+		return CIL_KEY_CONS_R2;
+	case CIL_CONS_R3:
+		return CIL_KEY_CONS_R3;
+	case CIL_CONS_L1:
+		return CIL_KEY_CONS_L1;
+	case CIL_CONS_L2:
+		return CIL_KEY_CONS_L2;
+	case CIL_CONS_H1:
+		return CIL_KEY_CONS_H1;
+	case CIL_CONS_H2:
+		return CIL_KEY_CONS_H2;
+
+	default:
+		break;
+	}
+
+	return "<unknown>";
+}
+
+#ifdef DISABLE_SYMVER
+int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_userprefixes_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+	int rc = SEPOL_ERR;
+	size_t str_len = 0;
+	int buf_pos = 0;
+	char *str_tmp = NULL;
+	struct cil_list_item *curr;
+	struct cil_userprefix *userprefix = NULL;
+	struct cil_user *user = NULL;
+
+	*out = NULL;
+
+	if (db->userprefixes->head == NULL) {
+		rc = SEPOL_OK;
+		*size = 0;
+		goto exit;
+	}
+
+	cil_list_for_each(curr, db->userprefixes) {
+		userprefix = curr->data;
+		user = userprefix->user;
+		str_len += strlen("user ") + strlen(user->datum.fqn) + strlen(" prefix ") + strlen(userprefix->prefix_str) + 2;
+	}
+
+	*size = str_len * sizeof(char);
+	str_len++;
+	str_tmp = cil_malloc(str_len * sizeof(char));
+	*out = str_tmp;
+
+	cil_list_for_each(curr, db->userprefixes) {
+		userprefix = curr->data;
+		user = userprefix->user;
+
+		buf_pos = snprintf(str_tmp, str_len, "user %s prefix %s;\n", user->datum.fqn,
+									userprefix->prefix_str);
+		str_len -= buf_pos;
+		str_tmp += buf_pos;
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+
+}
+
+#ifndef DISABLE_SYMVER
+int cil_userprefixes_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+	return cil_userprefixes_to_string_nopdb(db, out, size);
+}
+#endif
+
+static int cil_cats_to_ebitmap(struct cil_cats *cats, struct ebitmap* cats_ebitmap)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *i;
+	struct cil_list_item *j;
+	struct cil_cat* cat;
+	struct cil_catset *cs;
+	struct cil_tree_node *node;
+
+	if (cats == NULL) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	cil_list_for_each(i, cats->datum_expr) {
+		node = DATUM(i->data)->nodes->head->data;
+		if (node->flavor == CIL_CATSET) {
+			cs = (struct cil_catset*)i->data;
+			cil_list_for_each(j, cs->cats->datum_expr) {
+				cat = (struct cil_cat*)j->data;
+				rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+		} else {
+			cat = (struct cil_cat*)i->data;
+			rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int cil_level_equals(struct cil_level *low, struct cil_level *high)
+{
+	int rc;
+	struct ebitmap elow;
+	struct ebitmap ehigh;
+
+	if (strcmp(low->sens->datum.fqn, high->sens->datum.fqn)) {
+		rc = 0;
+		goto exit;
+	}
+
+	ebitmap_init(&elow);
+	ebitmap_init(&ehigh);
+
+	rc = cil_cats_to_ebitmap(low->cats, &elow);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_cats_to_ebitmap(high->cats, &ehigh);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return ebitmap_cmp(&elow, &ehigh);
+
+exit:
+	return rc;
+}
+
+static int __cil_level_strlen(struct cil_level *lvl)
+{
+	struct cil_list_item *item;
+	struct cil_cats *cats = lvl->cats;
+	int str_len = 0;
+	char *str1 = NULL;
+	char *str2 = NULL;
+	int first = -1;
+	int last = -1;
+
+	str_len += strlen(lvl->sens->datum.fqn);
+
+	if (cats && cats->datum_expr != NULL) {
+		str_len++; /* initial ":" */
+		cil_list_for_each(item, cats->datum_expr) {
+			struct cil_cat *cat = item->data;
+			if (first == -1) {
+				str1 = cat->datum.fqn;
+				first = cat->value;
+				last = first;
+			} else if (cat->value == last + 1) {
+				last++;
+				str2 = cat->datum.fqn;
+			} else {
+				if (first == last) {
+					str_len += strlen(str1) + strlen(cat->datum.fqn) + 1;
+				} else if (last == first + 1) {
+					str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2;
+				} else {
+					str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2;
+				}
+				first = -1;
+				last = -1;
+				if (item->next != NULL) {
+					str_len++; /* space for "," after */
+				}
+			}
+		}
+		if (first != -1) {
+			if (first == last) {
+				str_len += strlen(str1);
+			} else if (last == first + 1) {
+				str_len += strlen(str1) + strlen(str2) + 1;
+			} else {
+				str_len += strlen(str1) + strlen(str2) + 1;
+			}
+		}
+	}
+
+	return str_len;
+}
+
+static int __cil_level_to_string(struct cil_level *lvl, char *out)
+{
+	struct cil_list_item *item;
+	struct cil_cats *cats = lvl->cats;
+	int buf_pos = 0;
+	char *str_tmp = out;
+	char *str1 = NULL;
+	char *str2 = NULL;
+	int first = -1;
+	int last = -1;
+
+	buf_pos = sprintf(str_tmp, "%s", lvl->sens->datum.fqn);
+	str_tmp += buf_pos;
+
+	if (cats && cats->datum_expr != NULL) {
+		buf_pos = sprintf(str_tmp, ":");
+		str_tmp += buf_pos;
+
+		cil_list_for_each(item, cats->datum_expr) {
+			struct cil_cat *cat = item->data;
+			if (first == -1) {
+				str1 = cat->datum.fqn;
+				first = cat->value;
+				last = first;
+			} else if (cat->value == last + 1) {
+				last++;
+				str2 = cat->datum.fqn;
+			} else {
+				if (first == last) {
+					buf_pos = sprintf(str_tmp, "%s,%s", str1, cat->datum.fqn);
+					str_tmp += buf_pos;
+				} else if (last == first + 1) {
+					buf_pos = sprintf(str_tmp, "%s,%s,%s", str1, str2, cat->datum.fqn);
+					str_tmp += buf_pos;
+				} else {
+					buf_pos = sprintf(str_tmp, "%s.%s,%s",str1, str2, cat->datum.fqn);
+					str_tmp += buf_pos;
+				}
+				first = -1;
+				last = -1;
+				if (item->next != NULL) {
+					buf_pos = sprintf(str_tmp, ",");
+					str_tmp += buf_pos;
+				}
+			}
+		}
+		if (first != -1) {
+			if (first == last) {
+				buf_pos = sprintf(str_tmp, "%s", str1);
+				str_tmp += buf_pos;
+			} else if (last == first + 1) {
+				buf_pos = sprintf(str_tmp, "%s,%s", str1, str2);
+				str_tmp += buf_pos;
+			} else {
+				buf_pos = sprintf(str_tmp, "%s.%s",str1, str2);
+				str_tmp += buf_pos;
+			}
+		}
+	}
+
+	return str_tmp - out;
+}
+
+#ifdef DISABLE_SYMVER
+int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_selinuxusers_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+	size_t str_len = 0;
+	int buf_pos = 0;
+	char *str_tmp = NULL;
+	struct cil_list_item *curr;
+
+	if (db->selinuxusers->head == NULL) {
+		*size = 0;
+		*out = NULL;
+		return SEPOL_OK;
+	}
+
+	cil_list_for_each(curr, db->selinuxusers) {
+		struct cil_selinuxuser *selinuxuser = curr->data;
+		struct cil_user *user = selinuxuser->user;
+
+		str_len += strlen(selinuxuser->name_str) + strlen(user->datum.fqn) + 1;
+
+		if (db->mls == CIL_TRUE) {
+			struct cil_levelrange *range = selinuxuser->range;
+			str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2;
+		}
+
+		str_len++;
+	}
+
+	*size = str_len * sizeof(char);
+	str_tmp = cil_malloc(*size+1);
+	*out = str_tmp;
+
+	for(curr = db->selinuxusers->head; curr != NULL; curr = curr->next) {
+		struct cil_selinuxuser *selinuxuser = curr->data;
+		struct cil_user *user = selinuxuser->user;
+
+		buf_pos = sprintf(str_tmp, "%s:%s", selinuxuser->name_str, user->datum.fqn);
+		str_tmp += buf_pos;
+
+		if (db->mls == CIL_TRUE) {
+			struct cil_levelrange *range = selinuxuser->range;
+			buf_pos = sprintf(str_tmp, ":");
+			str_tmp += buf_pos;
+			buf_pos = __cil_level_to_string(range->low, str_tmp);
+			str_tmp += buf_pos;
+			buf_pos = sprintf(str_tmp, "-");
+			str_tmp += buf_pos;
+			buf_pos = __cil_level_to_string(range->high, str_tmp);
+			str_tmp += buf_pos;
+		}
+
+		buf_pos = sprintf(str_tmp, "\n");
+		str_tmp += buf_pos;
+	}
+
+	return SEPOL_OK;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_selinuxusers_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+	return cil_selinuxusers_to_string_nopdb(db, out, size);
+}
+#endif
+
+#ifdef DISABLE_SYMVER
+int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_filecons_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+	uint32_t i = 0;
+	int buf_pos = 0;
+	size_t str_len = 0;
+	char *str_tmp = NULL;
+	struct cil_sort *filecons = db->filecon;
+
+	for (i = 0; i < filecons->count; i++) {
+		struct cil_filecon *filecon = filecons->array[i];
+		struct cil_context *ctx = filecon->context;
+
+		str_len += strlen(filecon->path_str);
+
+		if (filecon->type != CIL_FILECON_ANY) {
+			/* If a type is specified,
+			   +2 for type string, +1 for tab */
+			str_len += 3;
+		}
+
+		if (ctx != NULL) {
+			struct cil_user *user = ctx->user;
+			struct cil_role *role = ctx->role;
+			struct cil_type *type = ctx->type;
+
+			str_len += (strlen(user->datum.fqn) + strlen(role->datum.fqn) + strlen(type->datum.fqn) + 3);
+
+			if (db->mls == CIL_TRUE) {
+				struct cil_levelrange *range = ctx->range;
+				if (cil_level_equals(range->low, range->high)) {
+					str_len += __cil_level_strlen(range->low) + 1;
+				} else {
+					str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2;
+				}
+			}
+		} else {
+			str_len += strlen("\t<<none>>");
+		}
+
+		str_len++;
+	}
+
+	*size = str_len * sizeof(char);
+	str_tmp = cil_malloc(*size+1);
+	*out = str_tmp;
+
+	for (i = 0; i < filecons->count; i++) {
+		struct cil_filecon *filecon = filecons->array[i];
+		struct cil_context *ctx = filecon->context;
+		const char *str_type = NULL;
+
+		buf_pos = sprintf(str_tmp, "%s", filecon->path_str);
+		str_tmp += buf_pos;
+
+		switch(filecon->type) {
+		case CIL_FILECON_FILE:
+			str_type = "\t--";
+			break;
+		case CIL_FILECON_DIR:
+			str_type = "\t-d";
+			break;
+		case CIL_FILECON_CHAR:
+			str_type = "\t-c";
+			break;
+		case CIL_FILECON_BLOCK:
+			str_type = "\t-b";
+			break;
+		case CIL_FILECON_SOCKET:
+			str_type = "\t-s";
+			break;
+		case CIL_FILECON_PIPE:
+			str_type = "\t-p";
+			break;
+		case CIL_FILECON_SYMLINK:
+			str_type = "\t-l";
+			break;
+		default:
+			str_type = "";
+			break;
+		}
+		buf_pos = sprintf(str_tmp, "%s", str_type);
+		str_tmp += buf_pos;
+
+		if (ctx != NULL) {
+			struct cil_user *user = ctx->user;
+			struct cil_role *role = ctx->role;
+			struct cil_type *type = ctx->type;
+
+			buf_pos = sprintf(str_tmp, "\t%s:%s:%s", user->datum.fqn, role->datum.fqn,
+							  type->datum.fqn);
+			str_tmp += buf_pos;
+
+			if (db->mls == CIL_TRUE) {
+				struct cil_levelrange *range = ctx->range;
+				buf_pos = sprintf(str_tmp, ":");
+				str_tmp += buf_pos;
+				buf_pos = __cil_level_to_string(range->low, str_tmp);
+				str_tmp += buf_pos;
+
+				if (!cil_level_equals(range->low, range->high)) {
+					buf_pos = sprintf(str_tmp, "-");
+					str_tmp += buf_pos;
+					buf_pos = __cil_level_to_string(range->high, str_tmp);
+					str_tmp += buf_pos;
+				}
+			}
+		} else {
+			buf_pos = sprintf(str_tmp, "\t<<none>>");
+			str_tmp += buf_pos;
+		}
+
+		buf_pos = sprintf(str_tmp, "\n");
+		str_tmp += buf_pos;
+	}
+
+	return SEPOL_OK;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_filecons_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+	return cil_filecons_to_string_nopdb(db, out, size);
+}
+#endif
+
+void cil_set_disable_dontaudit(struct cil_db *db, int disable_dontaudit)
+{
+	db->disable_dontaudit = disable_dontaudit;
+}
+
+void cil_set_disable_neverallow(struct cil_db *db, int disable_neverallow)
+{
+	db->disable_neverallow = disable_neverallow;
+}
+
+void cil_set_preserve_tunables(struct cil_db *db, int preserve_tunables)
+{
+	db->preserve_tunables = preserve_tunables;
+}
+
+int cil_set_handle_unknown(struct cil_db *db, int handle_unknown)
+{
+	int rc = 0;
+
+	switch (handle_unknown) {
+		case SEPOL_DENY_UNKNOWN:
+		case SEPOL_REJECT_UNKNOWN:
+		case SEPOL_ALLOW_UNKNOWN:
+			db->handle_unknown = handle_unknown;
+			break;
+		default:
+			cil_log(CIL_ERR, "Unknown value for handle-unknown: %i\n", handle_unknown);
+			rc = -1;
+	}
+
+	return rc;
+}
+
+void cil_set_mls(struct cil_db *db, int mls)
+{
+	db->mls = mls;
+}
+
+void cil_set_target_platform(struct cil_db *db, int target_platform)
+{
+	db->target_platform = target_platform;
+}
+
+void cil_set_policy_version(struct cil_db *db, int policy_version)
+{
+	db->policy_version = policy_version;
+}
+
+void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM])
+{
+	uint32_t i = 0;
+	for (i = 0; i < CIL_SYM_NUM; i++) {
+		cil_symtab_init(&symtab[i], symtab_sizes[i]);
+	}
+}
+
+void cil_symtab_array_destroy(symtab_t symtab[])
+{
+	int i = 0;
+	for (i = 0; i < CIL_SYM_NUM; i++) {
+		cil_symtab_destroy(&symtab[i]);
+	}
+}
+
+void cil_destroy_ast_symtabs(struct cil_tree_node *current)
+{
+	while (current) {
+		switch (current->flavor) {
+		case CIL_BLOCK:
+			cil_symtab_array_destroy(((struct cil_block*)current->data)->symtab);
+			break;
+		case CIL_IN:
+			cil_symtab_array_destroy(((struct cil_in*)current->data)->symtab);
+			break;
+		case CIL_CLASS:
+		case CIL_COMMON:
+		case CIL_MAP_CLASS:
+			cil_symtab_destroy(&((struct cil_class*)current->data)->perms);
+			break;
+		case CIL_MACRO:
+			cil_symtab_array_destroy(((struct cil_macro*)current->data)->symtab);
+			break;
+		case CIL_CONDBLOCK:
+			cil_symtab_array_destroy(((struct cil_condblock*)current->data)->symtab);
+			break;
+		default:
+			break;
+		}
+
+		if (current->cl_head) {
+			cil_destroy_ast_symtabs(current->cl_head);
+		}
+
+		current = current->next;
+	}
+}
+
+int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index)
+{
+	struct cil_tree_node *node = ast_node;
+	*symtab = NULL;
+	
+	if (sym_index == CIL_SYM_PERMS) {
+		/* Class statements are not blocks, so the passed node should be the class */
+		if (node->flavor == CIL_CLASS || node->flavor == CIL_MAP_CLASS ||
+			node->flavor == CIL_COMMON) {
+			*symtab = &((struct cil_class*)node->data)->perms;
+			return SEPOL_OK;
+		}
+		goto exit;
+	}
+
+	if (sym_index < CIL_SYM_BLOCKS || sym_index >= CIL_SYM_NUM) {
+		cil_log(CIL_ERR, "Invalid symtab type\n");
+		goto exit;
+	}
+
+	while (node != NULL && *symtab == NULL) {
+		switch (node->flavor) {
+		case CIL_ROOT:
+			*symtab = &((struct cil_root *)node->data)->symtab[sym_index];
+			break;
+		case CIL_BLOCK:
+			*symtab = &((struct cil_block*)node->data)->symtab[sym_index];
+			break;
+		case CIL_MACRO:
+			*symtab = &((struct cil_macro*)node->data)->symtab[sym_index];
+			break;
+		case CIL_IN:
+			/* In blocks only exist before resolving the AST */
+			*symtab = &((struct cil_in*)node->data)->symtab[sym_index];
+			break;
+		case CIL_CONDBLOCK: {
+			if (node->parent->flavor == CIL_TUNABLEIF) {
+				/* Cond blocks only exist before resolving the AST */
+				*symtab = &((struct cil_condblock*)node->data)->symtab[sym_index];
+			} else if (node->parent->flavor == CIL_BOOLEANIF) {
+				node = node->parent->parent;
+			}
+			break;
+		}
+		default:
+			node = node->parent;
+		}
+	}
+
+	if (*symtab == NULL) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(ast_node, CIL_ERR, "Failed to get symtab from node");
+	return SEPOL_ERR;	
+}
+
+void cil_sort_init(struct cil_sort **sort)
+{
+	*sort = cil_malloc(sizeof(**sort));
+
+	(*sort)->flavor = CIL_NONE;
+	(*sort)->count = 0;
+	(*sort)->index = 0;
+	(*sort)->array = NULL;
+}
+
+void cil_sort_destroy(struct cil_sort **sort)
+{
+	(*sort)->flavor = CIL_NONE;
+	(*sort)->count = 0;
+	(*sort)->index = 0;
+	if ((*sort)->array != NULL) {
+		free((*sort)->array);
+	}
+	(*sort)->array = NULL;
+
+	free(*sort);
+	*sort = NULL;
+}
+
+void cil_netifcon_init(struct cil_netifcon **netifcon)
+{
+	*netifcon = cil_malloc(sizeof(**netifcon));
+
+	(*netifcon)->interface_str = NULL;
+	(*netifcon)->if_context_str = NULL;
+	(*netifcon)->if_context = NULL;
+	(*netifcon)->packet_context_str = NULL;
+	(*netifcon)->packet_context = NULL;
+	(*netifcon)->context_str = NULL;
+}
+
+void cil_context_init(struct cil_context **context)
+{
+	*context = cil_malloc(sizeof(**context));
+
+	cil_symtab_datum_init(&(*context)->datum);
+	(*context)->user_str = NULL;
+	(*context)->user = NULL;
+	(*context)->role_str = NULL;
+	(*context)->role = NULL;
+	(*context)->type_str = NULL;
+	(*context)->type = NULL;
+	(*context)->range_str = NULL;
+	(*context)->range = NULL;
+}
+
+void cil_level_init(struct cil_level **level)
+{
+	*level = cil_malloc(sizeof(**level));
+
+	cil_symtab_datum_init(&(*level)->datum);
+	(*level)->sens_str = NULL;
+	(*level)->sens = NULL;
+	(*level)->cats = NULL;
+}
+
+void cil_levelrange_init(struct cil_levelrange **range)
+{
+	*range = cil_malloc(sizeof(**range));
+
+	cil_symtab_datum_init(&(*range)->datum);
+	(*range)->low_str = NULL;
+	(*range)->low = NULL;
+	(*range)->high_str = NULL;
+	(*range)->high = NULL;
+}
+
+void cil_sens_init(struct cil_sens **sens)
+{
+	*sens = cil_malloc(sizeof(**sens));
+
+	cil_symtab_datum_init(&(*sens)->datum);
+
+	(*sens)->cats_list = NULL;
+
+	(*sens)->ordered = CIL_FALSE;
+}
+
+void cil_block_init(struct cil_block **block)
+{
+	*block = cil_malloc(sizeof(**block));
+
+	cil_symtab_datum_init(&(*block)->datum);
+
+	cil_symtab_array_init((*block)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK]);
+
+	(*block)->is_abstract = CIL_FALSE;
+
+	(*block)->bi_nodes = NULL;
+}
+
+void cil_blockinherit_init(struct cil_blockinherit **inherit)
+{
+	*inherit = cil_malloc(sizeof(**inherit));
+	(*inherit)->block_str = NULL;
+	(*inherit)->block = NULL;
+}
+
+void cil_blockabstract_init(struct cil_blockabstract **abstract)
+{
+	*abstract = cil_malloc(sizeof(**abstract));
+	(*abstract)->block_str = NULL;
+}
+
+void cil_in_init(struct cil_in **in)
+{
+	*in = cil_malloc(sizeof(**in));
+
+	cil_symtab_array_init((*in)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_IN]);
+	(*in)->block_str = NULL;
+}
+
+void cil_class_init(struct cil_class **class)
+{
+	*class = cil_malloc(sizeof(**class));
+
+	cil_symtab_datum_init(&(*class)->datum);
+
+	cil_symtab_init(&(*class)->perms, CIL_CLASS_SYM_SIZE);
+
+	(*class)->num_perms = 0;
+	(*class)->common = NULL;
+	(*class)->ordered = CIL_FALSE;
+}
+
+void cil_classorder_init(struct cil_classorder **classorder)
+{
+	*classorder = cil_malloc(sizeof(**classorder));
+
+	(*classorder)->class_list_str = NULL;
+}
+
+void cil_classcommon_init(struct cil_classcommon **classcommon)
+{
+	*classcommon = cil_malloc(sizeof(**classcommon));
+
+	(*classcommon)->class_str = NULL;
+	(*classcommon)->common_str = NULL;
+}
+
+void cil_sid_init(struct cil_sid **sid)
+{
+	*sid = cil_malloc(sizeof(**sid));
+
+	cil_symtab_datum_init(&(*sid)->datum);
+
+	(*sid)->ordered = CIL_FALSE;
+	(*sid)->context = NULL;
+}
+
+void cil_sidcontext_init(struct cil_sidcontext **sidcontext)
+{
+	*sidcontext = cil_malloc(sizeof(**sidcontext));
+
+	(*sidcontext)->sid_str = NULL;
+	(*sidcontext)->context_str = NULL;
+	(*sidcontext)->context = NULL;
+}
+
+void cil_sidorder_init(struct cil_sidorder **sidorder)
+{
+	*sidorder = cil_malloc(sizeof(**sidorder));
+
+	(*sidorder)->sid_list_str = NULL;
+}
+
+void cil_userrole_init(struct cil_userrole **userrole)
+{
+	*userrole = cil_malloc(sizeof(**userrole));
+
+	(*userrole)->user_str = NULL;
+	(*userrole)->user = NULL;
+	(*userrole)->role_str = NULL;
+	(*userrole)->role = NULL;
+}
+
+void cil_userprefix_init(struct cil_userprefix **userprefix)
+{
+	*userprefix = cil_malloc(sizeof(**userprefix));
+
+	(*userprefix)->user_str = NULL;
+	(*userprefix)->user = NULL;
+	(*userprefix)->prefix_str = NULL;
+}
+
+void cil_selinuxuser_init(struct cil_selinuxuser **selinuxuser)
+{
+	*selinuxuser = cil_malloc(sizeof(**selinuxuser));
+
+	(*selinuxuser)->name_str = NULL;
+	(*selinuxuser)->user_str = NULL;
+	(*selinuxuser)->user = NULL;
+	(*selinuxuser)->range_str = NULL;
+	(*selinuxuser)->range = NULL;
+}
+
+void cil_roletype_init(struct cil_roletype **roletype)
+{
+	*roletype = cil_malloc(sizeof(**roletype));
+
+	(*roletype)->role_str = NULL;
+	(*roletype)->role = NULL;
+	(*roletype)->type_str = NULL;
+	(*roletype)->type = NULL;
+}
+
+void cil_roleattribute_init(struct cil_roleattribute **attr)
+{
+	*attr = cil_malloc(sizeof(**attr));
+
+	cil_symtab_datum_init(&(*attr)->datum);
+
+	(*attr)->expr_list = NULL;
+	(*attr)->roles = NULL;
+}
+
+void cil_roleattributeset_init(struct cil_roleattributeset **attrset)
+{
+	*attrset = cil_malloc(sizeof(**attrset));
+
+	(*attrset)->attr_str = NULL;
+	(*attrset)->str_expr = NULL;
+	(*attrset)->datum_expr = NULL;
+}
+
+void cil_typeattribute_init(struct cil_typeattribute **attr)
+{
+	*attr = cil_malloc(sizeof(**attr));
+
+	cil_symtab_datum_init(&(*attr)->datum);
+
+	(*attr)->expr_list = NULL;
+	(*attr)->types = NULL;
+	(*attr)->used = CIL_FALSE;
+}
+
+void cil_typeattributeset_init(struct cil_typeattributeset **attrset)
+{
+	*attrset = cil_malloc(sizeof(**attrset));
+
+	(*attrset)->attr_str = NULL;
+	(*attrset)->str_expr = NULL;
+	(*attrset)->datum_expr = NULL;
+}
+
+void cil_alias_init(struct cil_alias **alias)
+{
+	*alias = cil_malloc(sizeof(**alias));
+
+	(*alias)->actual = NULL;
+
+	cil_symtab_datum_init(&(*alias)->datum);
+}
+
+void cil_aliasactual_init(struct cil_aliasactual **aliasactual)
+{
+	*aliasactual = cil_malloc(sizeof(**aliasactual));
+
+	(*aliasactual)->alias_str = NULL;
+	(*aliasactual)->actual_str = NULL;
+}
+
+void cil_typepermissive_init(struct cil_typepermissive **typeperm)
+{
+	*typeperm = cil_malloc(sizeof(**typeperm));
+
+	(*typeperm)->type_str = NULL;
+	(*typeperm)->type = NULL;
+}
+
+void cil_name_init(struct cil_name **name)
+{
+	*name = cil_malloc(sizeof(**name));
+
+	cil_symtab_datum_init(&(*name)->datum);
+	(*name)->name_str = NULL;
+}
+
+void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans)
+{
+	*nametypetrans = cil_malloc(sizeof(**nametypetrans));
+
+	(*nametypetrans)->src_str = NULL;
+	(*nametypetrans)->src = NULL;
+	(*nametypetrans)->tgt_str = NULL;
+	(*nametypetrans)->tgt = NULL;
+	(*nametypetrans)->obj_str = NULL;
+	(*nametypetrans)->obj = NULL;
+	(*nametypetrans)->name_str = NULL;
+	(*nametypetrans)->name = NULL;
+	(*nametypetrans)->result_str = NULL;
+	(*nametypetrans)->result = NULL;
+}
+
+void cil_rangetransition_init(struct cil_rangetransition **rangetrans)
+{
+        *rangetrans = cil_malloc(sizeof(**rangetrans));
+
+	(*rangetrans)->src_str = NULL;
+	(*rangetrans)->src = NULL;
+	(*rangetrans)->exec_str = NULL;
+	(*rangetrans)->exec = NULL;
+	(*rangetrans)->obj_str = NULL;
+	(*rangetrans)->obj = NULL;
+	(*rangetrans)->range_str = NULL;
+	(*rangetrans)->range = NULL;
+}
+
+void cil_bool_init(struct cil_bool **cilbool)
+{
+	*cilbool = cil_malloc(sizeof(**cilbool));
+
+	cil_symtab_datum_init(&(*cilbool)->datum);
+	(*cilbool)->value = 0;
+}
+
+void cil_tunable_init(struct cil_tunable **ciltun)
+{
+	*ciltun = cil_malloc(sizeof(**ciltun));
+
+	cil_symtab_datum_init(&(*ciltun)->datum);
+	(*ciltun)->value = 0;
+}
+
+void cil_condblock_init(struct cil_condblock **cb)
+{
+	*cb = cil_malloc(sizeof(**cb));
+
+	(*cb)->flavor = CIL_NONE;
+	cil_symtab_array_init((*cb)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_CONDBLOCK]);
+}
+
+void cil_boolif_init(struct cil_booleanif **bif)
+{
+	*bif = cil_malloc(sizeof(**bif));
+
+	(*bif)->str_expr = NULL;
+	(*bif)->datum_expr = NULL;
+}
+
+void cil_tunif_init(struct cil_tunableif **tif)
+{
+	*tif = cil_malloc(sizeof(**tif));
+
+	(*tif)->str_expr = NULL;
+	(*tif)->datum_expr = NULL;
+}
+
+void cil_avrule_init(struct cil_avrule **avrule)
+{
+	*avrule = cil_malloc(sizeof(**avrule));
+
+	(*avrule)->is_extended = 0;
+	(*avrule)->rule_kind = CIL_NONE;
+	(*avrule)->src_str = NULL;
+	(*avrule)->src = NULL;
+	(*avrule)->tgt_str = NULL;
+	(*avrule)->tgt = NULL;
+	memset(&((*avrule)->perms), 0, sizeof((*avrule)->perms));
+}
+
+void cil_permissionx_init(struct cil_permissionx **permx)
+{
+	*permx = cil_malloc(sizeof(**permx));
+
+	cil_symtab_datum_init(&(*permx)->datum);
+	(*permx)->kind = CIL_NONE;
+	(*permx)->obj_str = NULL;
+	(*permx)->obj = NULL;
+	(*permx)->expr_str = NULL;
+	(*permx)->perms = NULL;
+}
+
+void cil_type_rule_init(struct cil_type_rule **type_rule)
+{
+	*type_rule = cil_malloc(sizeof(**type_rule));
+
+	(*type_rule)->rule_kind = CIL_NONE;
+	(*type_rule)->src_str = NULL;
+	(*type_rule)->src = NULL;
+	(*type_rule)->tgt_str = NULL;
+	(*type_rule)->tgt = NULL;
+	(*type_rule)->obj_str = NULL;
+	(*type_rule)->obj = NULL;
+	(*type_rule)->result_str = NULL;
+	(*type_rule)->result = NULL;
+}
+
+void cil_roletransition_init(struct cil_roletransition **role_trans)
+{
+	*role_trans = cil_malloc(sizeof(**role_trans));
+
+	(*role_trans)->src_str = NULL;
+	(*role_trans)->src = NULL;
+	(*role_trans)->tgt_str = NULL;
+	(*role_trans)->tgt = NULL;
+	(*role_trans)->obj_str = NULL;
+	(*role_trans)->obj = NULL;
+	(*role_trans)->result_str = NULL;
+	(*role_trans)->result = NULL;
+}
+
+void cil_roleallow_init(struct cil_roleallow **roleallow)
+{
+	*roleallow = cil_malloc(sizeof(**roleallow));
+
+	(*roleallow)->src_str = NULL;
+	(*roleallow)->src = NULL;
+	(*roleallow)->tgt_str = NULL;
+	(*roleallow)->tgt = NULL;
+}
+
+void cil_catset_init(struct cil_catset **catset)
+{
+	*catset = cil_malloc(sizeof(**catset));
+
+	cil_symtab_datum_init(&(*catset)->datum);
+	(*catset)->cats = NULL;
+}
+
+void cil_senscat_init(struct cil_senscat **senscat)
+{
+	*senscat = cil_malloc(sizeof(**senscat));
+
+	(*senscat)->sens_str = NULL;
+	(*senscat)->cats = NULL;
+}
+
+void cil_cats_init(struct cil_cats **cats)
+{
+	*cats = cil_malloc(sizeof(**cats));
+
+	(*cats)->evaluated = CIL_FALSE;
+	(*cats)->str_expr = NULL;
+	(*cats)->datum_expr = NULL;
+}
+
+void cil_filecon_init(struct cil_filecon **filecon)
+{
+	*filecon = cil_malloc(sizeof(**filecon));
+
+	(*filecon)->path_str = NULL;
+	(*filecon)->type = 0;
+	(*filecon)->context_str = NULL;
+	(*filecon)->context = NULL;
+}
+
+void cil_portcon_init(struct cil_portcon **portcon)
+{
+	*portcon = cil_malloc(sizeof(**portcon));
+	(*portcon)->proto = 0;
+	(*portcon)->port_low = 0;
+	(*portcon)->port_high = 0;
+	(*portcon)->context_str = NULL;
+	(*portcon)->context = NULL;
+}
+
+void cil_nodecon_init(struct cil_nodecon **nodecon)
+{
+	*nodecon = cil_malloc(sizeof(**nodecon));
+
+	(*nodecon)->addr_str = NULL;
+	(*nodecon)->addr = NULL;
+	(*nodecon)->mask_str = NULL;
+	(*nodecon)->mask = NULL;
+	(*nodecon)->context_str = NULL;
+	(*nodecon)->context = NULL;
+}
+
+void cil_genfscon_init(struct cil_genfscon **genfscon)
+{
+	*genfscon = cil_malloc(sizeof(**genfscon));
+
+	(*genfscon)->fs_str = NULL;
+	(*genfscon)->path_str = NULL;
+	(*genfscon)->context_str = NULL;
+	(*genfscon)->context = NULL;
+}
+
+void cil_pirqcon_init(struct cil_pirqcon **pirqcon)
+{
+	*pirqcon = cil_malloc(sizeof(**pirqcon));
+	
+	(*pirqcon)->pirq = 0;
+	(*pirqcon)->context_str = NULL;
+	(*pirqcon)->context = NULL;
+}
+
+void cil_iomemcon_init(struct cil_iomemcon **iomemcon)
+{
+	*iomemcon = cil_malloc(sizeof(**iomemcon));
+
+	(*iomemcon)->iomem_low = 0;
+	(*iomemcon)->iomem_high = 0;
+	(*iomemcon)->context_str = NULL;
+	(*iomemcon)->context = NULL;
+}
+
+void cil_ioportcon_init(struct cil_ioportcon **ioportcon)
+{
+	*ioportcon = cil_malloc(sizeof(**ioportcon));
+
+	(*ioportcon)->context_str = NULL;
+	(*ioportcon)->context = NULL;
+}
+
+void cil_pcidevicecon_init(struct cil_pcidevicecon **pcidevicecon)
+{
+	*pcidevicecon = cil_malloc(sizeof(**pcidevicecon));
+
+	(*pcidevicecon)->dev = 0;
+	(*pcidevicecon)->context_str = NULL;
+	(*pcidevicecon)->context = NULL;
+}
+
+void cil_devicetreecon_init(struct cil_devicetreecon **dtcon)
+{
+	*dtcon = cil_malloc(sizeof(**dtcon));
+
+	(*dtcon)->path = NULL;
+	(*dtcon)->context_str = NULL;
+	(*dtcon)->context = NULL;
+}
+
+void cil_fsuse_init(struct cil_fsuse **fsuse)
+{
+	*fsuse = cil_malloc(sizeof(**fsuse));
+
+	(*fsuse)->type = 0;
+	(*fsuse)->fs_str = NULL;
+	(*fsuse)->context_str = NULL;
+	(*fsuse)->context = NULL;
+}
+
+void cil_constrain_init(struct cil_constrain **constrain)
+{
+	*constrain = cil_malloc(sizeof(**constrain));
+
+	(*constrain)->classperms = NULL;
+	(*constrain)->str_expr = NULL;
+	(*constrain)->datum_expr = NULL;
+}
+
+void cil_validatetrans_init(struct cil_validatetrans **validtrans)
+{
+	*validtrans = cil_malloc(sizeof(**validtrans));
+
+	(*validtrans)->class_str = NULL;
+	(*validtrans)->class = NULL;
+	(*validtrans)->str_expr = NULL;
+	(*validtrans)->datum_expr = NULL;
+}
+
+void cil_ipaddr_init(struct cil_ipaddr **ipaddr)
+{
+	*ipaddr = cil_malloc(sizeof(**ipaddr));
+
+	cil_symtab_datum_init(&(*ipaddr)->datum);
+	memset(&(*ipaddr)->ip, 0, sizeof((*ipaddr)->ip));
+}
+
+void cil_perm_init(struct cil_perm **perm)
+{
+	*perm = cil_malloc(sizeof(**perm));
+
+	cil_symtab_datum_init(&(*perm)->datum);
+	(*perm)->value = 0;
+	(*perm)->classperms = NULL;
+}
+
+void cil_classpermission_init(struct cil_classpermission **cp)
+{
+	*cp = cil_malloc(sizeof(**cp));
+
+	cil_symtab_datum_init(&(*cp)->datum);
+	(*cp)->classperms = NULL;
+}
+
+void cil_classpermissionset_init(struct cil_classpermissionset **cps)
+{
+	*cps = cil_malloc(sizeof(**cps));
+
+	(*cps)->set_str = NULL;
+	(*cps)->classperms = NULL;
+}
+
+void cil_classperms_set_init(struct cil_classperms_set **cp_set)
+{
+	*cp_set = cil_malloc(sizeof(**cp_set));
+	(*cp_set)->set_str = NULL;
+	(*cp_set)->set = NULL;
+}
+
+void cil_classperms_init(struct cil_classperms **cp)
+{
+	*cp = cil_malloc(sizeof(**cp));
+	(*cp)->class_str = NULL;
+	(*cp)->class = NULL;
+	(*cp)->perm_strs = NULL;
+	(*cp)->perms = NULL;
+}
+
+void cil_classmapping_init(struct cil_classmapping **mapping)
+{
+	*mapping = cil_malloc(sizeof(**mapping));
+
+	(*mapping)->map_class_str = NULL;
+	(*mapping)->map_perm_str = NULL;
+	(*mapping)->classperms = NULL;
+}
+
+void cil_user_init(struct cil_user **user)
+{
+	*user = cil_malloc(sizeof(**user));
+
+	cil_symtab_datum_init(&(*user)->datum);
+	(*user)->bounds = NULL;
+	(*user)->roles = NULL;
+	(*user)->dftlevel = NULL;
+	(*user)->range = NULL;
+	(*user)->value = 0;
+}
+
+void cil_userattribute_init(struct cil_userattribute **attr)
+{
+	*attr = cil_malloc(sizeof(**attr));
+
+	cil_symtab_datum_init(&(*attr)->datum);
+
+	(*attr)->expr_list = NULL;
+	(*attr)->users = NULL;
+}
+
+void cil_userattributeset_init(struct cil_userattributeset **attrset)
+{
+	*attrset = cil_malloc(sizeof(**attrset));
+
+	(*attrset)->attr_str = NULL;
+	(*attrset)->str_expr = NULL;
+	(*attrset)->datum_expr = NULL;
+}
+
+void cil_userlevel_init(struct cil_userlevel **usrlvl)
+{
+	*usrlvl = cil_malloc(sizeof(**usrlvl));
+
+	(*usrlvl)->user_str = NULL;
+	(*usrlvl)->level_str = NULL;
+	(*usrlvl)->level = NULL;
+}
+
+void cil_userrange_init(struct cil_userrange **userrange)
+{
+	*userrange = cil_malloc(sizeof(**userrange));
+
+	(*userrange)->user_str = NULL;
+	(*userrange)->range_str = NULL;
+	(*userrange)->range = NULL;
+}
+
+void cil_role_init(struct cil_role **role)
+{
+	*role = cil_malloc(sizeof(**role));
+
+	cil_symtab_datum_init(&(*role)->datum);
+	(*role)->bounds = NULL;
+	(*role)->types = NULL;
+	(*role)->value = 0;
+}
+
+void cil_type_init(struct cil_type **type)
+{
+	*type = cil_malloc(sizeof(**type));
+
+	cil_symtab_datum_init(&(*type)->datum);
+	(*type)->bounds = NULL;
+	(*type)->value = 0;
+}
+
+void cil_cat_init(struct cil_cat **cat)
+{
+	*cat = cil_malloc(sizeof(**cat));
+
+	cil_symtab_datum_init(&(*cat)->datum);
+	(*cat)->ordered = CIL_FALSE;
+	(*cat)->value = 0;
+}
+
+void cil_catorder_init(struct cil_catorder **catorder)
+{
+	*catorder = cil_malloc(sizeof(**catorder));
+
+	(*catorder)->cat_list_str = NULL;
+}
+
+void cil_sensorder_init(struct cil_sensorder **sensorder)
+{
+	*sensorder = cil_malloc(sizeof(**sensorder));
+
+	(*sensorder)->sens_list_str = NULL;
+}
+
+void cil_args_init(struct cil_args **args)
+{
+	*args = cil_malloc(sizeof(**args));
+	(*args)->arg_str = NULL;
+	(*args)->arg = NULL;
+	(*args)->param_str = NULL;
+	(*args)->flavor = CIL_NONE;
+}
+
+void cil_call_init(struct cil_call **call)
+{
+	*call = cil_malloc(sizeof(**call));
+
+	(*call)->macro_str = NULL;
+	(*call)->macro = NULL;
+	(*call)->args_tree = NULL;
+	(*call)->args = NULL;
+	(*call)->copied = 0;
+}
+
+void cil_optional_init(struct cil_optional **optional)
+{
+	*optional = cil_malloc(sizeof(**optional));
+	(*optional)->enabled = CIL_TRUE;
+	cil_symtab_datum_init(&(*optional)->datum);
+}
+
+void cil_param_init(struct cil_param **param)
+{
+	*param = cil_malloc(sizeof(**param));
+
+	(*param)->str = NULL;
+	(*param)->flavor = CIL_NONE;
+}
+
+void cil_macro_init(struct cil_macro **macro)
+{
+	*macro = cil_malloc(sizeof(**macro));
+
+	cil_symtab_datum_init(&(*macro)->datum);
+	cil_symtab_array_init((*macro)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_MACRO]);
+	(*macro)->params = NULL;
+}
+
+void cil_policycap_init(struct cil_policycap **policycap)
+{
+	*policycap = cil_malloc(sizeof(**policycap));
+
+	cil_symtab_datum_init(&(*policycap)->datum);
+}
+
+void cil_bounds_init(struct cil_bounds **bounds)
+{
+	*bounds = cil_malloc(sizeof(**bounds));
+
+	(*bounds)->parent_str = NULL;
+	(*bounds)->child_str = NULL;
+}
+
+void cil_default_init(struct cil_default **def)
+{
+	*def = cil_malloc(sizeof(**def));
+
+	(*def)->flavor = CIL_NONE;
+	(*def)->class_strs = NULL;
+	(*def)->class_datums = NULL;
+}
+
+void cil_defaultrange_init(struct cil_defaultrange **def)
+{
+	*def = cil_malloc(sizeof(**def));
+
+	(*def)->class_strs = NULL;
+	(*def)->class_datums = NULL;
+}
+
+void cil_handleunknown_init(struct cil_handleunknown **unk)
+{
+	*unk = cil_malloc(sizeof(**unk));
+}
+
+void cil_mls_init(struct cil_mls **mls)
+{
+	*mls = cil_malloc(sizeof(**mls));
+	(*mls)->value = 0;
+}
+
+void cil_src_info_init(struct cil_src_info **info)
+{
+	*info = cil_malloc(sizeof(**info));
+	(*info)->is_cil = 0;
+	(*info)->path = NULL;
+}
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
new file mode 100644
index 0000000..5d03127
--- /dev/null
+++ b/libsepol/cil/src/cil_binary.c
@@ -0,0 +1,4808 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/hierarchy.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_binary.h"
+#include "cil_symtab.h"
+#include "cil_find.h"
+
+/* There are 44000 filename_trans in current fedora policy. 1.33 times this is the recommended
+ * size of a hashtable. The next power of 2 of this is 2 ** 16.
+ */
+#define FILENAME_TRANS_TABLE_SIZE (1 << 16)
+#define RANGE_TRANS_TABLE_SIZE (1 << 13)
+#define ROLE_TRANS_TABLE_SIZE (1 << 10)
+#define AVRULEX_TABLE_SIZE (1 <<  10)
+#define PERMS_PER_CLASS 32
+
+struct cil_args_binary {
+	const struct cil_db *db;
+	policydb_t *pdb;
+	struct cil_list *neverallows;
+	int pass;
+	hashtab_t filename_trans_table;
+	hashtab_t range_trans_table;
+	hashtab_t role_trans_table;
+	hashtab_t avrulex_ioctl_table;
+	void **type_value_to_cil;
+};
+
+struct cil_args_booleanif {
+	const struct cil_db *db;
+	policydb_t *pdb;
+	cond_node_t *cond_node;
+	enum cil_flavor cond_flavor;
+	hashtab_t filename_trans_table;
+};
+
+static int __cil_get_sepol_user_datum(policydb_t *pdb, struct cil_symtab_datum *datum, user_datum_t **sepol_user)
+{
+	*sepol_user = hashtab_search(pdb->p_users.table, datum->fqn);
+	if (*sepol_user == NULL) {
+		cil_log(CIL_INFO, "Failed to find user %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_get_sepol_role_datum(policydb_t *pdb, struct cil_symtab_datum *datum, role_datum_t **sepol_role)
+{
+	*sepol_role = hashtab_search(pdb->p_roles.table, datum->fqn);
+	if (*sepol_role == NULL) {
+		cil_log(CIL_INFO, "Failed to find role %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_get_sepol_type_datum(policydb_t *pdb, struct cil_symtab_datum *datum, type_datum_t **sepol_type)
+{
+	*sepol_type = hashtab_search(pdb->p_types.table, datum->fqn);
+	if (*sepol_type == NULL) {
+		cil_log(CIL_INFO, "Failed to find type %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_get_sepol_class_datum(policydb_t *pdb, struct cil_symtab_datum *datum, class_datum_t **sepol_class)
+{
+	*sepol_class = hashtab_search(pdb->p_classes.table, datum->fqn);
+	if (*sepol_class == NULL) {
+		cil_log(CIL_INFO, "Failed to find class %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_get_sepol_cat_datum(policydb_t *pdb, struct cil_symtab_datum *datum, cat_datum_t **sepol_cat)
+{
+	*sepol_cat = hashtab_search(pdb->p_cats.table, datum->fqn);
+	if (*sepol_cat == NULL) {
+		cil_log(CIL_INFO, "Failed to find category %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_get_sepol_level_datum(policydb_t *pdb, struct cil_symtab_datum *datum, level_datum_t **sepol_level)
+{
+	*sepol_level = hashtab_search(pdb->p_levels.table, datum->fqn);
+	if (*sepol_level == NULL) {
+		cil_log(CIL_INFO, "Failed to find level %s in sepol hashtab\n", datum->fqn);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_expand_user(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+	struct cil_tree_node *node = datum->nodes->head->data;
+	struct cil_user *user = NULL;
+	struct cil_userattribute *attr = NULL;
+
+	if (node->flavor == CIL_USERATTRIBUTE) {
+		attr = (struct cil_userattribute *)datum;
+		if (ebitmap_cpy(new, attr->users)) {
+			cil_log(CIL_ERR, "Failed to copy user bits\n");
+			goto exit;
+		}
+	} else {
+		user = (struct cil_user *)datum;
+		ebitmap_init(new);
+		if (ebitmap_set_bit(new, user->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set user bit\n");
+			ebitmap_destroy(new);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_expand_role(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	if (node->flavor == CIL_ROLEATTRIBUTE) {
+		struct cil_roleattribute *attr = (struct cil_roleattribute *)datum;
+		if (ebitmap_cpy(new, attr->roles)) {
+			cil_log(CIL_ERR, "Failed to copy role bits\n");
+			goto exit;
+		}
+	} else {
+		struct cil_role *role = (struct cil_role *)datum;
+		ebitmap_init(new);
+		if (ebitmap_set_bit(new, role->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set role bit\n");
+			ebitmap_destroy(new);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_expand_type(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	if (node->flavor == CIL_TYPEATTRIBUTE) {
+		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+		if (ebitmap_cpy(new, attr->types)) {
+			cil_log(CIL_ERR, "Failed to copy type bits\n");
+			goto exit;
+		}
+	} else {
+		struct cil_type *type = (struct cil_type *)datum;
+		ebitmap_init(new);
+		if (ebitmap_set_bit(new, type->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set type bit\n");
+			ebitmap_destroy(new);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static ocontext_t *cil_add_ocontext(ocontext_t **head, ocontext_t **tail)
+{
+	ocontext_t *new = cil_malloc(sizeof(ocontext_t));
+	memset(new, 0, sizeof(ocontext_t));
+	if (*tail) {
+		(*tail)->next = new;
+	} else {
+		*head = new;
+	}
+	*tail = new;
+
+	return new;
+}
+
+int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	struct cil_tree_node *node = cil_common->datum.nodes->head->data;
+	struct cil_tree_node *cil_perm = node->cl_head;
+	common_datum_t *sepol_common = cil_malloc(sizeof(*sepol_common));
+	memset(sepol_common, 0, sizeof(common_datum_t));
+
+	key = cil_strdup(cil_common->datum.fqn);
+	rc = symtab_insert(pdb, SYM_COMMONS, key, sepol_common, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		free(sepol_common);
+		goto exit;
+	}
+	sepol_common->s.value = value;
+
+	rc = symtab_init(&sepol_common->permissions, PERM_SYMTAB_SIZE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	while (cil_perm != NULL) {
+		struct cil_perm *curr = cil_perm->data;
+		perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm));
+		memset(sepol_perm, 0, sizeof(perm_datum_t));
+
+		key = cil_strdup(curr->datum.fqn);
+		rc = hashtab_insert(sepol_common->permissions.table, key, sepol_perm);
+		if (rc != SEPOL_OK) {
+			free(sepol_perm);
+			goto exit;
+		}
+		sepol_perm->s.value = sepol_common->permissions.nprim + 1;
+		sepol_common->permissions.nprim++;
+		cil_perm = cil_perm->next;
+	}
+
+	*common_out = sepol_common;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	return rc;
+}
+
+int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr_class;
+
+	cil_list_for_each(curr_class, db->classorder) {
+		struct cil_class *cil_class = curr_class->data;
+		uint32_t value = 0;
+		char *key = NULL;
+		int class_index;
+		struct cil_tree_node *curr;
+		common_datum_t *sepol_common = NULL;
+		class_datum_t *sepol_class = cil_malloc(sizeof(*sepol_class));
+		memset(sepol_class, 0, sizeof(class_datum_t));
+
+		key = cil_strdup(cil_class->datum.fqn);
+		rc = symtab_insert(pdb, SYM_CLASSES, key, sepol_class, SCOPE_DECL, 0, &value);
+		if (rc != SEPOL_OK) {
+			free(sepol_class);
+			free(key);
+			goto exit;
+		}
+		sepol_class->s.value = value;
+		class_index = value;
+		class_value_to_cil[class_index] = cil_class;
+
+		rc = symtab_init(&sepol_class->permissions, PERM_SYMTAB_SIZE);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		if (cil_class->common != NULL) {
+			int i;
+			struct cil_class *cil_common = cil_class->common;
+
+			key = cil_class->common->datum.fqn;
+			sepol_common = hashtab_search(pdb->p_commons.table, key);
+			if (sepol_common == NULL) {
+				rc = cil_common_to_policydb(pdb, cil_common, &sepol_common);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+			sepol_class->comdatum = sepol_common;
+			sepol_class->comkey = cil_strdup(key);
+			sepol_class->permissions.nprim += sepol_common->permissions.nprim;
+
+			for (curr = NODE(cil_class->common)->cl_head, i = 1; curr; curr = curr->next, i++) {
+				struct cil_perm *cil_perm = curr->data;
+				perm_value_to_cil[class_index][i] = cil_perm;
+			}
+		}
+
+		for (curr = NODE(cil_class)->cl_head; curr; curr = curr->next) {
+			struct cil_perm *cil_perm = curr->data;
+			perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm));
+			memset(sepol_perm, 0, sizeof(perm_datum_t));
+
+			key = cil_strdup(cil_perm->datum.fqn);
+			rc = hashtab_insert(sepol_class->permissions.table, key, sepol_perm);
+			if (rc != SEPOL_OK) {
+				free(sepol_perm);
+				free(key);
+				goto exit;
+			}
+			sepol_perm->s.value = sepol_class->permissions.nprim + 1;
+			sepol_class->permissions.nprim++;
+			perm_value_to_cil[class_index][sepol_perm->s.value] = cil_perm;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	role_datum_t *sepol_role = cil_malloc(sizeof(*sepol_role));
+	role_datum_init(sepol_role);
+
+	if (cil_role->datum.fqn == CIL_KEY_OBJECT_R) {
+		/* special case
+		 * object_r defaults to 1 in libsepol symtab */
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	key = cil_strdup(cil_role->datum.fqn);
+	rc = symtab_insert(pdb, SYM_ROLES, (hashtab_key_t)key, sepol_role, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	if (ebitmap_set_bit(&sepol_role->dominates, value - 1, 1)) {
+		cil_log(CIL_INFO, "Failed to set dominates bit for role\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+	sepol_role->s.value = value;
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	role_datum_destroy(sepol_role);
+	free(sepol_role);
+	return rc;
+}
+
+int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role)
+{
+	int rc = SEPOL_ERR;
+	role_datum_t *sepol_role = NULL;
+	role_datum_t *sepol_parent = NULL;
+
+	if (cil_role->bounds) {
+		rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role), &sepol_role);
+		if (rc != SEPOL_OK) goto exit;
+
+		rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role->bounds), &sepol_parent);
+		if (rc != SEPOL_OK) goto exit;
+	
+		sepol_role->bounds = sepol_parent->s.value;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to insert role bounds for role %s\n", cil_role->datum.fqn);
+	return SEPOL_ERR;
+}
+
+int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role)
+{
+	int rc = SEPOL_ERR;
+
+	if (role->types) {
+		role_datum_t *sepol_role = NULL;
+		type_datum_t *sepol_type = NULL;
+		ebitmap_node_t *tnode;
+		unsigned int i;
+
+		rc = __cil_get_sepol_role_datum(pdb, DATUM(role), &sepol_role);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(role->types, tnode, i) {
+			if (!ebitmap_get_bit(role->types, i)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+			if (rc != SEPOL_OK) goto exit;
+
+			if (ebitmap_set_bit(&sepol_role->types.types, sepol_type->s.value - 1, 1)) {
+				cil_log(CIL_INFO, "Failed to set type bit for role\n");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[])
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	type_datum_t *sepol_type = cil_malloc(sizeof(*sepol_type));
+	type_datum_init(sepol_type);
+
+	sepol_type->flavor = TYPE_TYPE;
+
+	key = cil_strdup(cil_type->datum.fqn);
+	rc = symtab_insert(pdb, SYM_TYPES, key, sepol_type, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_type->s.value = value;
+	sepol_type->primary = 1;
+
+	type_value_to_cil[value] = cil_type;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	type_datum_destroy(sepol_type);
+	free(sepol_type);
+	return rc;
+}
+
+int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_type = NULL;
+	type_datum_t *sepol_parent = NULL;
+
+	if (cil_type->bounds) {
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type), &sepol_type);
+		if (rc != SEPOL_OK) goto exit;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type->bounds), &sepol_parent);
+		if (rc != SEPOL_OK) goto exit;
+	
+		sepol_type->bounds = sepol_parent->s.value;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to insert type bounds for type %s\n", cil_type->datum.fqn);
+	return SEPOL_ERR;
+}
+
+int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	type_datum_t *sepol_type = NULL;
+	type_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias));
+	type_datum_init(sepol_alias);
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_alias->actual), &sepol_type);
+	if (rc != SEPOL_OK) goto exit;
+
+	sepol_alias->flavor = TYPE_TYPE;
+
+	key = cil_strdup(cil_alias->datum.fqn);
+	rc = symtab_insert(pdb, SYM_TYPES, key, sepol_alias, SCOPE_DECL, 0, NULL);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_alias->s.value = sepol_type->s.value;
+	sepol_alias->primary = 0;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	type_datum_destroy(sepol_alias);
+	free(sepol_alias);
+	return rc;
+}
+
+int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_type = NULL;
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_typeperm->type), &sepol_type);
+	if (rc != SEPOL_OK) goto exit;
+
+	if (ebitmap_set_bit(&pdb->permissive_map, sepol_type->s.value, 1)) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	type_datum_destroy(sepol_type);
+	free(sepol_type);
+	return rc;
+
+}
+
+int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[])
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	type_datum_t *sepol_attr = NULL;
+
+	if (cil_attr->used == CIL_FALSE) {
+		return SEPOL_OK;		
+	}
+
+	sepol_attr = cil_malloc(sizeof(*sepol_attr));
+	type_datum_init(sepol_attr);
+
+	sepol_attr->flavor = TYPE_ATTRIB;
+
+	key = cil_strdup(cil_attr->datum.fqn);
+	rc = symtab_insert(pdb, SYM_TYPES, key, sepol_attr, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_attr->s.value = value;
+	sepol_attr->primary = 1;
+
+	type_value_to_cil[value] = cil_attr;
+
+	return SEPOL_OK;
+
+exit:
+	type_datum_destroy(sepol_attr);
+	free(sepol_attr);
+	return rc;
+}
+
+int __cil_typeattr_bitmap_init(policydb_t *pdb)
+{
+	int rc = SEPOL_ERR;
+
+	pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t));
+	pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t));
+
+	uint32_t i = 0;
+	for (i = 0; i < pdb->p_types.nprim; i++) {
+		ebitmap_init(&pdb->type_attr_map[i]);
+		ebitmap_init(&pdb->attr_type_map[i]);
+		if (ebitmap_set_bit(&pdb->type_attr_map[i], i, 1)) {
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		if (pdb->type_val_to_struct[i] && pdb->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
+			if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *db, struct cil_typeattribute *cil_attr)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	type_datum_t *sepol_type = NULL;
+	ebitmap_node_t *tnode;
+	unsigned int i;
+
+	if (cil_attr->used == CIL_FALSE) {
+		return SEPOL_OK;
+	}
+
+	if (pdb->type_attr_map == NULL) {
+		rc = __cil_typeattr_bitmap_init(pdb);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_attr), &sepol_type);
+	if (rc != SEPOL_OK) goto exit;
+
+	value = sepol_type->s.value;
+
+	ebitmap_for_each_bit(cil_attr->types, tnode, i) {
+		if (!ebitmap_get_bit(cil_attr->types, i)) continue;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_set_bit(&pdb->type_attr_map[sepol_type->s.value - 1], value - 1, 1);
+		ebitmap_set_bit(&pdb->attr_type_map[value - 1], sepol_type->s.value - 1, 1);
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
+int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap)
+{
+	int rc = SEPOL_ERR;
+	int capnum;
+
+	capnum = sepol_polcap_getnum(cil_polcap->datum.fqn);
+	if (capnum == -1) {
+		goto exit;
+	}
+
+	if (ebitmap_set_bit(&pdb->policycaps, capnum, 1)) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	user_datum_t *sepol_user = cil_malloc(sizeof(*sepol_user));
+	user_datum_init(sepol_user);
+
+	key = cil_strdup(cil_user->datum.fqn);
+	rc = symtab_insert(pdb, SYM_USERS, key, sepol_user, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_user->s.value = value;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	user_datum_destroy(sepol_user);
+	free(sepol_user);
+	return rc;
+}
+
+int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+	int rc = SEPOL_ERR;
+	user_datum_t *sepol_user = NULL;
+	user_datum_t *sepol_parent = NULL;
+
+	if (cil_user->bounds) {
+		rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user);
+		if (rc != SEPOL_OK) goto exit;
+
+		rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user->bounds), &sepol_parent);
+		if (rc != SEPOL_OK) goto exit;
+	
+		sepol_user->bounds = sepol_parent->s.value;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to insert user bounds for user %s\n", cil_user->datum.fqn);
+	return SEPOL_ERR;
+}
+
+int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user)
+{
+	int rc = SEPOL_ERR;
+	user_datum_t *sepol_user = NULL;
+	role_datum_t *sepol_role = NULL;
+	ebitmap_node_t *rnode = NULL;
+	unsigned int i;
+
+	if (user->roles) {
+		rc = __cil_get_sepol_user_datum(pdb, DATUM(user), &sepol_user);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		ebitmap_for_each_bit(user->roles, rnode, i) {
+			if (!ebitmap_get_bit(user->roles, i)) {
+				continue;
+			}
+
+			rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+
+			if (ebitmap_set_bit(&sepol_user->roles.roles, sepol_role->s.value - 1, 1)) {
+				cil_log(CIL_INFO, "Failed to set role bit for user\n");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	cond_bool_datum_t *sepol_bool = cil_malloc(sizeof(*sepol_bool));
+	memset(sepol_bool, 0, sizeof(cond_bool_datum_t));
+
+	key = cil_strdup(cil_bool->datum.fqn);
+	rc = symtab_insert(pdb, SYM_BOOLS, key, sepol_bool, SCOPE_DECL, 0, &value);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_bool->s.value = value;
+	sepol_bool->state = cil_bool->value;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	free(sepol_bool);
+	return rc;
+}
+
+int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	struct cil_list_item *curr_cat;
+	struct cil_cat *cil_cat = NULL;
+	cat_datum_t *sepol_cat = NULL;
+
+	cil_list_for_each(curr_cat, db->catorder) {
+		cil_cat = curr_cat->data;
+		sepol_cat = cil_malloc(sizeof(*sepol_cat));
+		cat_datum_init(sepol_cat);
+
+		key = cil_strdup(cil_cat->datum.fqn);
+		rc = symtab_insert(pdb, SYM_CATS, key, sepol_cat, SCOPE_DECL, 0, &value);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		sepol_cat->s.value = value;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	cat_datum_destroy(sepol_cat);
+	free(sepol_cat);
+	return rc;
+}
+
+int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	cat_datum_t *sepol_cat;
+	cat_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_cat));
+	cat_datum_init(sepol_alias);
+
+	rc = __cil_get_sepol_cat_datum(pdb, DATUM(cil_alias->actual), &sepol_cat);
+	if (rc != SEPOL_OK) goto exit;
+
+	key = cil_strdup(cil_alias->datum.fqn);
+	rc = symtab_insert(pdb, SYM_CATS, key, sepol_alias, SCOPE_DECL, 0, NULL);
+	if (rc != SEPOL_OK) {
+		free(key);
+		goto exit;
+	}
+	sepol_alias->s.value = sepol_cat->s.value;
+	sepol_alias->isalias = 1;
+
+	return SEPOL_OK;
+
+exit:
+	free(key);
+	cat_datum_destroy(sepol_alias);
+	free(sepol_alias);
+	return rc;
+}
+
+int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	uint32_t value = 0;
+	char *key = NULL;
+	struct cil_list_item *curr;
+	struct cil_sens *cil_sens = NULL;
+	level_datum_t *sepol_level = NULL;
+	mls_level_t *mls_level = NULL;
+
+	cil_list_for_each(curr, db->sensitivityorder) {
+		cil_sens = curr->data;
+		sepol_level = cil_malloc(sizeof(*sepol_level));
+		mls_level = cil_malloc(sizeof(*mls_level));
+		level_datum_init(sepol_level);
+		mls_level_init(mls_level);
+
+		key = cil_strdup(cil_sens->datum.fqn);
+		rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_level, SCOPE_DECL, 0, &value);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		mls_level->sens = value;
+		sepol_level->level = mls_level;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	level_datum_destroy(sepol_level);
+	mls_level_destroy(mls_level);
+	free(sepol_level);
+	free(mls_level);
+	free(key);
+	return rc;
+}
+
+int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	mls_level_t *mls_level = NULL;
+	level_datum_t *sepol_level = NULL;
+	level_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias));
+	level_datum_init(sepol_alias);
+
+	rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_alias->actual), &sepol_level);
+	if (rc != SEPOL_OK) goto exit;
+
+	key = cil_strdup(cil_alias->datum.fqn);
+	rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_alias, SCOPE_DECL, 0, NULL);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	mls_level = cil_malloc(sizeof(*mls_level));
+	mls_level_init(mls_level);
+
+	rc = mls_level_cpy(mls_level, sepol_level->level);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sepol_alias->level = mls_level;
+	sepol_alias->defined = 1;
+	sepol_alias->isalias = 1;
+
+	return SEPOL_OK;
+
+exit:
+	level_datum_destroy(sepol_alias);
+	free(sepol_level);
+	free(key);
+	return rc;
+}
+
+int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_OK;
+	avtab_ptr_t avtab_ptr = NULL;
+	cond_av_list_t *cond_list = NULL;
+
+	avtab_ptr = avtab_insert_nonunique(avtab, avtab_key, avtab_datum);
+	if (!avtab_ptr) {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	// parse_context needs to be non-NULL for conditional rules to be
+	// written to the binary. it is normally used for finding duplicates,
+	// but cil checks that earlier, so we don't use it. it just needs to be
+	// set
+	avtab_ptr->parse_context = (void*)1;
+
+	cond_list = cil_malloc(sizeof(cond_av_list_t));
+	memset(cond_list, 0, sizeof(cond_av_list_t));
+
+	cond_list->node = avtab_ptr;
+
+	if (cond_flavor == CIL_CONDTRUE) {
+      cond_list->next = cond_node->true_list;
+      cond_node->true_list = cond_list;
+	} else {
+      cond_list->next = cond_node->false_list;
+      cond_node->false_list = cond_list;
+	}
+
+exit:
+	return rc;
+}
+
+avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list)
+{
+	cond_av_list_t *cur_av;
+
+	for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
+		if (cur_av->node->key.source_type == key->source_type &&
+		    cur_av->node->key.target_type == key->target_type &&
+		    cur_av->node->key.target_class == key->target_class &&
+			(cur_av->node->key.specified & key->specified))
+
+			return &cur_av->node->datum;
+
+	}
+	return NULL;
+}
+
+int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_OK;
+	avtab_key_t avtab_key;
+	avtab_datum_t avtab_datum;
+	avtab_ptr_t existing;	
+
+	avtab_key.source_type = src;
+	avtab_key.target_type = tgt;
+	avtab_key.target_class = obj;
+
+	switch (kind) {
+	case CIL_TYPE_TRANSITION:
+		avtab_key.specified = AVTAB_TRANSITION;
+		break;
+	case CIL_TYPE_CHANGE:
+		avtab_key.specified = AVTAB_CHANGE;
+		break;
+	case CIL_TYPE_MEMBER:
+		avtab_key.specified = AVTAB_MEMBER;
+		break;
+	default:
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	avtab_datum.data = res;
+	
+	existing = avtab_search_node(&pdb->te_avtab, &avtab_key);
+	if (existing) {
+		/* Don't add duplicate type rule and warn if they conflict.
+		 * A warning should have been previously given if there is a
+		 * non-duplicate rule using the same key.
+		 */
+		if (existing->datum.data != res) {
+			cil_log(CIL_ERR, "Conflicting type rules\n");
+			rc = SEPOL_ERR;
+		}
+		goto exit;
+	}
+
+	if (!cond_node) {
+		rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum);
+	} else {
+		existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key);
+		if (existing) {
+			cond_av_list_t *this_list;
+			cond_av_list_t *other_list;
+			avtab_datum_t *search_datum;
+
+			if (cond_flavor == CIL_CONDTRUE) {
+				this_list = cond_node->true_list;
+				other_list = cond_node->false_list;
+			} else {
+				this_list = cond_node->false_list;
+				other_list = cond_node->true_list;
+			}
+
+			search_datum = cil_cond_av_list_search(&avtab_key, other_list);
+			if (search_datum == NULL) {
+				if (existing->datum.data != res) {
+					cil_log(CIL_ERR, "Conflicting type rules\n");
+					rc = SEPOL_ERR;
+					goto exit;
+				}
+
+				search_datum = cil_cond_av_list_search(&avtab_key, this_list);
+				if (search_datum) {
+					goto exit;
+				}
+			}
+		}
+		rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor);
+	}
+
+exit:
+	return rc;
+}
+
+int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_ERR;
+	uint16_t kind = cil_rule->rule_kind;
+	type_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_obj = NULL;
+	struct cil_list *class_list;
+	type_datum_t *sepol_result = NULL;
+	ebitmap_t src_bitmap, tgt_bitmap;
+	ebitmap_node_t *node1, *node2;
+	unsigned int i, j;
+	struct cil_list_item *c;
+
+	rc = __cil_expand_type(cil_rule->src, &src_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_expand_type(cil_rule->tgt, &tgt_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	class_list = cil_expand_class(cil_rule->obj);
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_rule->result), &sepol_result);
+	if (rc != SEPOL_OK) goto exit;
+
+	ebitmap_for_each_bit(&src_bitmap, node1, i) {
+		if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+			if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+			if (rc != SEPOL_OK) goto exit;
+
+			cil_list_for_each(c, class_list) {
+				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+				if (rc != SEPOL_OK) goto exit;
+
+				rc = __cil_insert_type_rule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, sepol_result->s.value, cond_node, cond_flavor);
+				if (rc != SEPOL_OK) goto exit;
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&src_bitmap);
+	ebitmap_destroy(&tgt_bitmap);
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return rc;
+}
+
+int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule)
+{
+	return  __cil_type_rule_to_avtab(pdb, db, cil_rule, NULL, CIL_FALSE);
+}
+
+int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor, hashtab_t filename_trans_table)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_obj = NULL;
+	struct cil_list *class_list;
+	type_datum_t *sepol_result = NULL;
+	filename_trans_t *new = NULL;
+	ebitmap_t src_bitmap, tgt_bitmap;
+	ebitmap_node_t *node1, *node2;
+	unsigned int i, j;
+	struct cil_list_item *c;
+	char *name = DATUM(typetrans->name)->name;
+	uint32_t *otype = NULL;
+
+	if (name == CIL_KEY_STAR) {
+		struct cil_type_rule trans;
+		trans.rule_kind = CIL_TYPE_TRANSITION;
+		trans.src = typetrans->src;
+		trans.tgt = typetrans->tgt;
+		trans.obj = typetrans->obj;
+		trans.result = typetrans->result;
+		return __cil_type_rule_to_avtab(pdb, db, &trans, cond_node, cond_flavor);
+	}
+
+	rc = __cil_expand_type(typetrans->src, &src_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_expand_type(typetrans->tgt, &tgt_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	class_list = cil_expand_class(typetrans->obj);
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(typetrans->result), &sepol_result);
+	if (rc != SEPOL_OK) goto exit;
+
+	ebitmap_for_each_bit(&src_bitmap, node1, i) {
+		if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+			if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+			if (rc != SEPOL_OK) goto exit;
+
+			cil_list_for_each(c, class_list) {
+				int add = CIL_TRUE;
+				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+				if (rc != SEPOL_OK) goto exit;
+
+				new = cil_malloc(sizeof(*new));
+				memset(new, 0, sizeof(*new));
+				new->stype = sepol_src->s.value;
+				new->ttype = sepol_tgt->s.value;
+				new->tclass = sepol_obj->s.value;
+				new->otype = sepol_result->s.value;
+				new->name = cil_strdup(name);
+
+				rc = hashtab_insert(filename_trans_table, (hashtab_key_t)new, &(new->otype));
+				if (rc != SEPOL_OK) {
+					if (rc == SEPOL_EEXIST) {
+						add = CIL_FALSE;
+						otype = hashtab_search(filename_trans_table, (hashtab_key_t)new);
+						if (new->otype != *otype) {
+							cil_log(CIL_ERR, "Conflicting name type transition rules\n");
+						} else {
+							rc = SEPOL_OK;
+						}
+					} else {
+						cil_log(CIL_ERR, "Out of memory\n");
+					}
+				}
+
+				if (add == CIL_TRUE) {
+					new->next = pdb->filename_trans;
+					pdb->filename_trans = new;
+				} else {
+					free(new->name);
+					free(new);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&src_bitmap);
+	ebitmap_destroy(&tgt_bitmap);
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return rc;
+}
+
+int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, hashtab_t filename_trans_table)
+{
+	return  __cil_typetransition_to_avtab(pdb, db, typetrans, NULL, CIL_FALSE, filename_trans_table);
+}
+
+int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum)
+{
+	int rc;
+	perm_datum_t *sepol_perm;
+	common_datum_t *sepol_common;
+
+	sepol_perm = hashtab_search(sepol_class->permissions.table, perm_str);
+	if (sepol_perm == NULL) {
+		sepol_common = sepol_class->comdatum;
+		sepol_perm = hashtab_search(sepol_common->permissions.table, perm_str);
+		if (sepol_perm == NULL) {
+			cil_log(CIL_ERR, "Failed to find datum for perm %s\n", perm_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+	*datum |= 1 << (sepol_perm->s.value - 1);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	struct cil_list_item *curr_perm;
+	struct cil_perm *cil_perm;
+	uint32_t data = 0;
+
+	cil_list_for_each(curr_perm, perms) {
+		cil_perm = curr_perm->data;
+		key = cil_perm->datum.fqn;
+
+		rc = __perm_str_to_datum(key, sepol_class, &data);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	*datum = data;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_OK;
+	avtab_key_t avtab_key;
+	avtab_datum_t avtab_datum;
+	avtab_datum_t *avtab_dup = NULL;
+
+	avtab_key.source_type = src;
+	avtab_key.target_type = tgt;
+	avtab_key.target_class = obj;
+	
+	switch (kind) {
+	case CIL_AVRULE_ALLOWED:
+		avtab_key.specified = AVTAB_ALLOWED;
+		break;
+	case CIL_AVRULE_AUDITALLOW:
+		avtab_key.specified = AVTAB_AUDITALLOW;
+		break;
+	case CIL_AVRULE_DONTAUDIT:
+		avtab_key.specified = AVTAB_AUDITDENY;
+		break;
+	default:
+		rc = SEPOL_ERR;
+		goto exit;
+		break;
+	}
+
+	if (!cond_node) {
+		avtab_dup = avtab_search(&pdb->te_avtab, &avtab_key);
+		if (!avtab_dup) {
+			avtab_datum.data = data;
+			rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum);
+		} else {
+			if (kind == CIL_AVRULE_DONTAUDIT)
+				avtab_dup->data &= data;
+			else
+				avtab_dup->data |= data;
+		}
+	} else {
+		avtab_datum.data = data;
+		rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor);
+	}
+
+exit:
+	return rc;
+}
+
+int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_class = NULL;
+	uint32_t data = 0;
+
+	rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_perms_to_datum(cp->perms, sepol_class, &data);
+	if (rc != SEPOL_OK) goto exit;
+
+	if (data == 0) {
+		/* No permissions, so don't insert rule. Maybe should return an error? */
+		return SEPOL_OK;
+	}
+
+	if (kind == CIL_AVRULE_DONTAUDIT) {
+		data = ~data;
+	}
+
+	rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_insert_avrule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_class->s.value, data, cond_node, cond_flavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				rc = __cil_avrule_expand_helper(pdb, kind, src, tgt, cp, cond_node, cond_flavor);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					rc = __cil_avrule_expand(pdb, kind, src, tgt, cmp->classperms, cond_node, cond_flavor);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}	
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = __cil_avrule_expand(pdb, kind, src, tgt, cp->classperms, cond_node, cond_flavor);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+	int rc = SEPOL_ERR;
+	uint16_t kind = cil_avrule->rule_kind;
+	struct cil_symtab_datum *src = NULL;
+	struct cil_symtab_datum *tgt = NULL;
+	struct cil_list *classperms = cil_avrule->perms.classperms;
+
+	if (cil_avrule->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) {
+		// Do not add dontaudit rules to binary
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	src = cil_avrule->src;
+	tgt = cil_avrule->tgt;
+
+	if (tgt->fqn == CIL_KEY_SELF) {
+		ebitmap_t type_bitmap;
+		ebitmap_node_t *tnode;
+		unsigned int i;
+
+		rc = __cil_expand_type(src, &type_bitmap);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+			if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+			src = DATUM(db->val_to_type[i]);
+			rc = __cil_avrule_expand(pdb, kind, src, src, classperms, cond_node, cond_flavor);
+			if (rc != SEPOL_OK) {
+				ebitmap_destroy(&type_bitmap);
+				goto exit;
+			}
+		}
+		ebitmap_destroy(&type_bitmap);
+	} else {
+		rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor);
+		if (rc != SEPOL_OK) goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule)
+{
+	return __cil_avrule_to_avtab(pdb, db, cil_avrule, NULL, CIL_FALSE);
+}
+
+// Copied from checkpolicy/policy_define.c
+
+/* 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, struct avtab_extended_perms *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);
+	}
+}
+
+
+#define IOC_DRIV(x) (x >> 8)
+#define IOC_FUNC(x) (x & 0xff)
+
+int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list)
+{
+	ebitmap_node_t *node;
+	unsigned int i;
+	uint16_t low = 0, high = 0;
+	struct avtab_extended_perms *partial = NULL;
+	struct avtab_extended_perms *complete = NULL;
+	int start_new_range;
+
+	cil_list_init(xperms_list, CIL_NONE);
+
+	start_new_range = 1;
+
+	ebitmap_for_each_bit(xperms, node, i) {
+		if (!ebitmap_get_bit(xperms, i)) continue;
+
+		if (start_new_range) {
+			low = i;
+			start_new_range = 0;
+		}
+
+		// continue if the current bit isn't the end of the driver function or the next bit is set
+		if (IOC_FUNC(i) != 0xff && ebitmap_get_bit(xperms, i + 1)) {
+			continue;
+		}
+
+		// if we got here, i is the end of this range (either becuase the func
+		// is 0xff or the next bit isn't set). The next time around we are
+		// going to need a start a new range
+		high = i;
+		start_new_range = 1;
+
+		if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) {
+			if (!complete) {
+				complete = cil_calloc(1, sizeof(*complete));
+				complete->driver = 0x0;
+				complete->specified = AVTAB_XPERMS_IOCTLDRIVER;
+			}
+
+			__avrule_xperm_setrangebits(IOC_DRIV(low), IOC_DRIV(low), complete);
+		} else {
+			if (partial && partial->driver != IOC_DRIV(low)) {
+				cil_list_append(*xperms_list, CIL_NONE, partial);
+				partial = NULL;
+			}
+
+			if (!partial) {
+				partial = cil_calloc(1, sizeof(*partial));
+				partial->driver = IOC_DRIV(low);
+				partial->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+			}
+
+			__avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial);
+		}
+	}
+
+	if (partial) {
+		cil_list_append(*xperms_list, CIL_NONE, partial);
+	}
+
+	if (complete) {
+		cil_list_append(*xperms_list, CIL_NONE, complete);
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args)
+{
+	int rc = SEPOL_OK;
+	struct policydb *pdb;
+	avtab_key_t *avtab_key;
+	avtab_datum_t avtab_datum;
+	struct cil_list *xperms_list = NULL;
+	struct cil_list_item *item;
+	class_datum_t *sepol_obj;
+	uint32_t data = 0;
+
+	avtab_key = (avtab_key_t *)k;
+	pdb = args;
+
+	sepol_obj = pdb->class_val_to_struct[avtab_key->target_class - 1];
+
+	// setting the data for an extended avtab isn't really neccessary because
+	// it is ignored by the kernel. However, neverallow checking requires that
+	// the data value be set, so set it for that to work.
+	rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	avtab_datum.data = data;
+
+	rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_for_each(item, xperms_list) {
+		avtab_datum.xperms = item->data;
+		rc = avtab_insert(&pdb->te_avtab, avtab_key, &avtab_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	if (xperms_list != NULL) {
+		cil_list_for_each(item, xperms_list) {
+			free(item->data);
+		}
+		cil_list_destroy(&xperms_list, CIL_FALSE);
+	}
+
+	// hashtab_t does not have a way to free keys or datum since it doesn't
+	// know what they are. We won't need the keys/datum after this function, so
+	// clean them up here.
+	free(avtab_key);
+	ebitmap_destroy(datum);
+	free(datum);
+
+	return rc;
+}
+
+int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms)
+{
+	uint16_t specified;
+	avtab_key_t *avtab_key;
+	ebitmap_t *hashtab_xperms;
+	int rc = SEPOL_ERR;
+
+	switch (kind) {
+	case CIL_AVRULE_ALLOWED:
+		specified = AVTAB_XPERMS_ALLOWED;
+		break;
+	case CIL_AVRULE_AUDITALLOW:
+		specified = AVTAB_XPERMS_AUDITALLOW;
+		break;
+	case CIL_AVRULE_DONTAUDIT:
+		specified = AVTAB_XPERMS_DONTAUDIT;
+		break;
+	default:
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	avtab_key = cil_malloc(sizeof(*avtab_key));
+	avtab_key->source_type = src;
+	avtab_key->target_type = tgt;
+	avtab_key->target_class = obj;
+	avtab_key->specified = specified;
+
+	hashtab_xperms = (ebitmap_t *)hashtab_search(h, (hashtab_key_t)avtab_key);
+	if (!hashtab_xperms) {
+		hashtab_xperms = cil_malloc(sizeof(*hashtab_xperms));
+		rc = ebitmap_cpy(hashtab_xperms, xperms);
+		if (rc != SEPOL_OK) {
+			free(avtab_key);
+			goto exit;
+		}
+		rc = hashtab_insert(h, (hashtab_key_t)avtab_key, hashtab_xperms);
+		if (rc != SEPOL_OK) {
+			free(avtab_key);
+			goto exit;
+		}
+	} else {
+		free(avtab_key);
+		rc = ebitmap_union(hashtab_xperms, xperms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_obj = NULL;
+	struct cil_list *class_list = NULL;
+	struct cil_list_item *c;
+
+	rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt);
+	if (rc != SEPOL_OK) goto exit;
+
+	class_list = cil_expand_class(permx->obj);
+
+	cil_list_for_each(c, class_list) {
+		rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+		if (rc != SEPOL_OK) goto exit;
+
+		switch (permx->kind) {
+		case  CIL_PERMX_KIND_IOCTL:
+			rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms);
+			if (rc != SEPOL_OK) goto exit;
+			break;
+		default:
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	cil_list_destroy(&class_list, CIL_FALSE);
+
+	return rc;
+}
+
+int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args)
+{
+	int rc = SEPOL_ERR;
+	uint16_t kind;
+	struct cil_symtab_datum *src = NULL;
+	struct cil_symtab_datum *tgt = NULL;
+	ebitmap_t type_bitmap;
+	ebitmap_node_t *tnode;
+	unsigned int i;
+
+	ebitmap_init(&type_bitmap);
+
+	if (cil_avrulex->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) {
+		// Do not add dontaudit rules to binary
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	kind = cil_avrulex->rule_kind;
+	src = cil_avrulex->src;
+	tgt = cil_avrulex->tgt;
+
+	if (tgt->fqn == CIL_KEY_SELF) {
+		rc = __cil_expand_type(src, &type_bitmap);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+			if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+			src = DATUM(db->val_to_type[i]);
+			rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, src, cil_avrulex->perms.x.permx, args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else {
+		rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args);
+		if (rc != SEPOL_OK) goto exit;
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&type_bitmap);
+
+	return rc;
+}
+
+int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+	int rc;
+	enum cil_flavor flavor;
+	struct cil_args_booleanif *args = extra_args;
+	const struct cil_db *db = args->db;
+	policydb_t *pdb = args->pdb;
+	cond_node_t *cond_node = args->cond_node;
+	enum cil_flavor cond_flavor = args->cond_flavor;
+	struct cil_type_rule *cil_type_rule;
+	struct cil_avrule *cil_avrule;
+	struct cil_nametypetransition *cil_typetrans;
+	hashtab_t filename_trans_table = args->filename_trans_table;
+
+	flavor = node->flavor;
+	switch (flavor) {
+	case CIL_NAMETYPETRANSITION:
+		cil_typetrans = (struct cil_nametypetransition*)node->data;
+		if (DATUM(cil_typetrans->name)->fqn != CIL_KEY_STAR) {
+			cil_log(CIL_ERR, "typetransition with file name not allowed within a booleanif block.\n");
+			cil_tree_log(node, CIL_ERR,"Invalid typetransition statement");
+			goto exit;
+		}
+		rc = __cil_typetransition_to_avtab(pdb, db, cil_typetrans, cond_node, cond_flavor, filename_trans_table);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_ERR, "Failed to insert type transition into avtab");
+			goto exit;
+		}
+		break;
+	case CIL_TYPE_RULE:
+		cil_type_rule = node->data;
+		rc = __cil_type_rule_to_avtab(pdb, db, cil_type_rule, cond_node, cond_flavor);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_ERR, "Failed to insert typerule into avtab");
+			goto exit;
+		}
+		break;
+	case CIL_AVRULE:
+		cil_avrule = node->data;
+		rc = __cil_avrule_to_avtab(pdb, db, cil_avrule, cond_node, cond_flavor);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_ERR, "Failed to insert avrule into avtab");
+			goto exit;
+		}
+		break;
+	case CIL_CALL:
+	case CIL_TUNABLEIF:
+		break;
+	default:
+		cil_tree_log(node, CIL_ERR, "Invalid statement within booleanif");
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out);
+
+static void __cil_expr_to_string_helper(struct cil_list_item *curr, enum cil_flavor flavor, char **out)
+{
+	char *c;
+
+	if (curr->flavor == CIL_DATUM) {
+		*out = cil_strdup(DATUM(curr->data)->fqn);
+	} else if (curr->flavor == CIL_LIST) {
+		__cil_expr_to_string(curr->data, flavor, &c);
+		cil_asprintf(out, "(%s)", c);
+		free(c);
+	} else if (flavor == CIL_PERMISSIONX) {
+		// permissionx expressions aren't resolved into anything, so curr->flavor
+		// is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those
+		*out = cil_strdup(curr->data);
+	}
+}
+
+static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out)
+{
+	struct cil_list_item *curr;
+	char *s1 = NULL;
+	char *s2 = NULL;
+	enum cil_flavor op;
+
+	if (expr == NULL || expr->head == NULL) {
+		*out = cil_strdup("");
+		return;
+	}
+
+	curr = expr->head;
+
+	if (curr->flavor == CIL_OP) {
+		op = (enum cil_flavor)curr->data;
+
+		if (op == CIL_ALL) {
+			*out = cil_strdup(CIL_KEY_ALL);
+		} else if (op == CIL_RANGE) {
+			__cil_expr_to_string_helper(curr->next, flavor, &s1);
+			__cil_expr_to_string_helper(curr->next->next, flavor, &s2);
+			cil_asprintf(out, "%s %s %s", CIL_KEY_RANGE, s1, s2);
+			free(s1);
+			free(s2);
+		} else {
+			__cil_expr_to_string_helper(curr->next, flavor, &s1);
+
+			if (op == CIL_NOT) {
+				cil_asprintf(out, "%s %s", CIL_KEY_NOT, s1);
+				free(s1);
+			} else {
+				char *opstr = "";
+
+				__cil_expr_to_string_helper(curr->next->next, flavor, &s2);
+
+				if (op == CIL_OR) {
+					opstr = CIL_KEY_OR;
+				} else if (op == CIL_AND) {
+					opstr = CIL_KEY_AND;
+				} else if (op == CIL_XOR) {
+					opstr = CIL_KEY_XOR;
+				}
+
+				cil_asprintf(out, "%s %s %s", opstr, s1, s2);
+				free(s1);
+				free(s2);
+			}
+		}
+	} else {
+		char *c1 = NULL;
+		char *c2 = NULL;
+		__cil_expr_to_string_helper(curr, flavor, &c1);
+		for (curr = curr->next; curr; curr = curr->next) {
+			__cil_expr_to_string_helper(curr, flavor, &s1);
+			cil_asprintf(&c2, "%s %s", c1, s1);
+			free(c1);
+			free(s1);
+			c1 = c2;
+		}
+		*out = c1;
+	}
+}
+
+static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail);
+
+static int __cil_cond_item_to_sepol_expr(policydb_t *pdb, struct cil_list_item *item, cond_expr_t **head, cond_expr_t **tail)
+{
+	if (item == NULL) {
+		goto exit;
+	} else if (item->flavor == CIL_DATUM) {
+		char *key = DATUM(item->data)->fqn;
+		cond_bool_datum_t *sepol_bool = hashtab_search(pdb->p_bools.table, key);
+		if (sepol_bool == NULL) {
+			cil_log(CIL_INFO, "Failed to find boolean\n");
+			goto exit;
+		}
+		*head = cil_malloc(sizeof(cond_expr_t));
+		(*head)->next = NULL;
+		(*head)->expr_type = COND_BOOL;
+		(*head)->bool = sepol_bool->s.value;
+		*tail = *head;
+	} else if (item->flavor == CIL_LIST) {
+		struct cil_list *l = item->data;
+		int rc = __cil_cond_expr_to_sepol_expr_helper(pdb, l, head, tail);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	} else {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *item = cil_expr->head;
+	enum cil_flavor flavor = cil_expr->flavor;
+	cond_expr_t *op, *h1, *h2, *t1, *t2;
+
+	if (flavor != CIL_BOOL) {
+		cil_log(CIL_INFO, "Expected boolean expression\n");
+		goto exit;
+	}
+
+	if (item == NULL) {
+		goto exit;
+	} else if (item->flavor == CIL_OP) {
+		enum cil_flavor cil_op = (enum cil_flavor)item->data;
+
+		op = cil_malloc(sizeof(*op));
+		op->bool = 0;
+		op->next = NULL;
+
+		switch (cil_op) {
+		case CIL_NOT:
+			op->expr_type = COND_NOT;
+			break;
+		case CIL_OR:
+			op->expr_type = COND_OR;
+			break;
+		case CIL_AND:
+			op->expr_type = COND_AND;
+			break;
+		case CIL_XOR:
+			op->expr_type = COND_XOR;
+			break;
+		case CIL_EQ:
+			op->expr_type = COND_EQ;
+			break;
+		case CIL_NEQ:
+			op->expr_type = COND_NEQ;
+			break;
+		default:
+			goto exit;
+		}
+
+		rc = __cil_cond_item_to_sepol_expr(pdb, item->next, &h1, &t1);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to get first operand of conditional expression\n");
+			free(op);
+			goto exit;
+		}
+
+		if (cil_op == CIL_NOT) {
+			*head = h1;
+			t1->next = op;
+			*tail = op;
+		} else {
+			rc = __cil_cond_item_to_sepol_expr(pdb, item->next->next, &h2, &t2);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to get second operand of conditional expression\n");
+				free(op);
+				cond_expr_destroy(h1);
+				goto exit;
+			}
+
+			*head = h1;
+			t1->next = h2;
+			t2->next = op;
+			*tail = op;
+		}
+	} else {
+		rc = __cil_cond_item_to_sepol_expr(pdb, item, &h1, &t1);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to get initial item in conditional list\n");
+			goto exit;
+		}
+		*head = h1;
+		for (item = item->next; item; item = item->next) {
+			rc = __cil_cond_item_to_sepol_expr(pdb, item, &h2, &t2);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to get item in conditional list\n");
+				cond_expr_destroy(*head);
+				goto exit;
+			}
+			op = cil_malloc(sizeof(*op));
+			op->bool = 0;
+			op->next = NULL;
+			op->expr_type = COND_OR;
+			t1->next = h2;
+			t2->next = op;
+			t1 = op;
+		}
+		*tail = t1;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_cond_expr_to_sepol_expr(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **sepol_expr)
+{
+	int rc;
+	cond_expr_t *head, *tail;
+	
+	rc = __cil_cond_expr_to_sepol_expr_helper(pdb, cil_expr, &head, &tail);
+	if (rc != SEPOL_OK) {
+		return SEPOL_ERR;
+	}
+	*sepol_expr = head;
+
+	return SEPOL_OK;
+}
+
+int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_booleanif bool_args;
+	struct cil_booleanif *cil_boolif = (struct cil_booleanif*)node->data;
+	struct cil_tree_node *cb_node = node->cl_head;
+	struct cil_tree_node *true_node = NULL;
+	struct cil_tree_node *false_node = NULL;
+	struct cil_tree_node *tmp_node = NULL;
+	cond_node_t *tmp_cond = NULL;
+	cond_node_t *cond_node = NULL;
+	int was_created;
+	int swapped = CIL_FALSE;
+	cond_av_list_t tmp_cl;
+
+	tmp_cond = cond_node_create(pdb, NULL);
+	if (tmp_cond == NULL) {
+		rc = SEPOL_ERR;
+		cil_tree_log(node, CIL_INFO, "Failed to create sepol conditional node");
+		goto exit;
+	}
+	
+	rc = __cil_cond_expr_to_sepol_expr(pdb, cil_boolif->datum_expr, &tmp_cond->expr);
+	if (rc != SEPOL_OK) {
+		cil_tree_log(node, CIL_INFO, "Failed to convert CIL conditional expression to sepol expression");
+		goto exit;
+	}
+
+	tmp_cond->true_list = &tmp_cl;
+
+	rc = cond_normalize_expr(pdb, tmp_cond);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (tmp_cond->false_list != NULL) {
+		tmp_cond->true_list = NULL;
+		swapped = CIL_TRUE;
+	}
+
+	cond_node = cond_node_find(pdb, tmp_cond, pdb->cond_list, &was_created);
+	if (cond_node == NULL) {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (was_created) {
+		cond_node->next = pdb->cond_list;
+		pdb->cond_list = cond_node;
+	}
+
+	cond_expr_destroy(tmp_cond->expr);
+	free(tmp_cond);
+
+	for (cb_node = node->cl_head; cb_node != NULL; cb_node = cb_node->next) {
+		if (cb_node->flavor == CIL_CONDBLOCK) {
+			struct cil_condblock *cb = cb_node->data;
+			if (cb->flavor == CIL_CONDTRUE) {
+					true_node = cb_node;
+			} else if (cb->flavor == CIL_CONDFALSE) {
+					false_node = cb_node;
+			}
+		}
+	}
+
+	if (swapped) {
+		tmp_node = true_node;
+		true_node = false_node;
+		false_node = tmp_node;
+	}
+
+	bool_args.db = db;
+	bool_args.pdb = pdb;
+	bool_args.cond_node = cond_node;
+	bool_args.filename_trans_table = filename_trans_table;
+
+	if (true_node != NULL) {
+		bool_args.cond_flavor = CIL_CONDTRUE;
+		rc = cil_tree_walk(true_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(true_node, CIL_ERR, "Failure while walking true conditional block");
+			goto exit;
+		}
+	}
+
+	if (false_node != NULL) {
+		bool_args.cond_flavor = CIL_CONDFALSE;
+		rc = cil_tree_walk(false_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(false_node, CIL_ERR, "Failure while walking false conditional block");
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table)
+{
+	int rc = SEPOL_ERR;
+	role_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_obj = NULL;
+	struct cil_list *class_list;
+	role_datum_t *sepol_result = NULL;
+	role_trans_t *new = NULL;
+	uint32_t *new_role = NULL;
+	ebitmap_t role_bitmap, type_bitmap;
+	ebitmap_node_t *rnode, *tnode;
+	unsigned int i, j;
+	struct cil_list_item *c;
+
+	rc = __cil_expand_role(DATUM(roletrans->src), &role_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_expand_type(roletrans->tgt, &type_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	class_list = cil_expand_class(roletrans->obj);
+
+	rc = __cil_get_sepol_role_datum(pdb, DATUM(roletrans->result), &sepol_result);
+	if (rc != SEPOL_OK) goto exit;
+
+	ebitmap_for_each_bit(&role_bitmap, rnode, i) {
+		if (!ebitmap_get_bit(&role_bitmap, i)) continue;
+
+		rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&type_bitmap, tnode, j) {
+			if (!ebitmap_get_bit(&type_bitmap, j)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+			if (rc != SEPOL_OK) goto exit;
+
+			cil_list_for_each(c, class_list) {
+				int add = CIL_TRUE;
+				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+				if (rc != SEPOL_OK) goto exit;
+
+				new = cil_malloc(sizeof(*new));
+				memset(new, 0, sizeof(*new));
+				new->role = sepol_src->s.value;
+				new->type = sepol_tgt->s.value;
+				new->tclass = sepol_obj->s.value;
+				new->new_role = sepol_result->s.value;
+
+				rc = SEPOL_OK;
+				rc = hashtab_insert(role_trans_table, (hashtab_key_t)new, &(new->new_role));
+				if (rc != SEPOL_OK) {
+					if (rc == SEPOL_EEXIST) {
+						add = CIL_FALSE;
+						new_role = hashtab_search(role_trans_table, (hashtab_key_t)new);
+						if (new->new_role != *new_role) {
+							cil_log(CIL_ERR, "Conflicting role transition rules\n");
+						} else {
+							rc = SEPOL_OK;
+						}
+					} else {
+						cil_log(CIL_ERR, "Out of memory\n");
+					}
+				}
+
+				if (add == CIL_TRUE) {
+					new->next = pdb->role_tr;
+					pdb->role_tr = new;
+				} else {
+					free(new);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&role_bitmap);
+	ebitmap_destroy(&type_bitmap);
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return rc;
+}
+
+int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow)
+{
+	int rc = SEPOL_ERR;
+	role_datum_t *sepol_src = NULL;
+	role_datum_t *sepol_tgt = NULL;
+	role_allow_t *sepol_roleallow = NULL;
+	ebitmap_t src_bitmap, tgt_bitmap;
+	ebitmap_node_t *node1, *node2;
+	unsigned int i, j;
+
+	rc = __cil_expand_role(roleallow->src, &src_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_expand_role(roleallow->tgt, &tgt_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	ebitmap_for_each_bit(&src_bitmap, node1, i) {
+		if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+		rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+			if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+			rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[j]), &sepol_tgt);
+			if (rc != SEPOL_OK) goto exit;
+
+			sepol_roleallow = cil_malloc(sizeof(*sepol_roleallow));
+			memset(sepol_roleallow, 0, sizeof(role_allow_t));
+			sepol_roleallow->role = sepol_src->s.value;
+			sepol_roleallow->new_role = sepol_tgt->s.value;
+
+			sepol_roleallow->next = pdb->role_allow;
+			pdb->role_allow = sepol_roleallow;
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&src_bitmap);
+	ebitmap_destroy(&tgt_bitmap);
+	return rc;
+}
+
+int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr)
+{
+	int rc = SEPOL_ERR;
+
+	if (expr_flavor == CIL_USER) {
+		user_datum_t *sepol_user = NULL;
+		ebitmap_t user_bitmap;
+		ebitmap_node_t *unode;
+		unsigned int i;
+
+		rc = __cil_expand_user(item->data, &user_bitmap);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&user_bitmap, unode, i) {
+			if (!ebitmap_get_bit(&user_bitmap, i)) {
+				continue;
+			}
+
+			rc = __cil_get_sepol_user_datum(pdb, DATUM(db->val_to_user[i]), &sepol_user);
+			if (rc != SEPOL_OK) {
+				ebitmap_destroy(&user_bitmap);
+				goto exit;
+			}
+
+			if (ebitmap_set_bit(&expr->names, sepol_user->s.value - 1, 1)) {
+				ebitmap_destroy(&user_bitmap);
+				goto exit;
+			}
+		}
+		ebitmap_destroy(&user_bitmap);
+	} else if (expr_flavor == CIL_ROLE) {
+		role_datum_t *sepol_role = NULL;
+		ebitmap_t role_bitmap;
+		ebitmap_node_t *rnode;
+		unsigned int i;
+
+		rc = __cil_expand_role(item->data, &role_bitmap);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&role_bitmap, rnode, i) {
+			if (!ebitmap_get_bit(&role_bitmap, i)) continue;
+
+			rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role);
+			if (rc != SEPOL_OK) {
+				ebitmap_destroy(&role_bitmap);
+				goto exit;
+			}
+
+			if (ebitmap_set_bit(&expr->names, sepol_role->s.value - 1, 1)) {
+				ebitmap_destroy(&role_bitmap);
+				goto exit;
+			}
+		}
+		ebitmap_destroy(&role_bitmap);
+	} else if (expr_flavor == CIL_TYPE) {
+		type_datum_t *sepol_type = NULL;
+		ebitmap_t type_bitmap;
+		ebitmap_node_t *tnode;
+		unsigned int i;
+
+		if (pdb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) {
+			rc = __cil_get_sepol_type_datum(pdb, item->data, &sepol_type);
+			if (rc != SEPOL_OK) {
+				ebitmap_destroy(&type_bitmap);
+				goto exit;
+			}
+
+			if (ebitmap_set_bit(&expr->type_names->types, sepol_type->s.value - 1, 1)) {
+				ebitmap_destroy(&type_bitmap);
+				goto exit;
+			}
+		}
+
+		rc = __cil_expand_type(item->data, &type_bitmap);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+			if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+			if (rc != SEPOL_OK) {
+				ebitmap_destroy(&type_bitmap);
+				goto exit;
+			}
+
+			if (ebitmap_set_bit(&expr->names, sepol_type->s.value - 1, 1)) {
+				ebitmap_destroy(&type_bitmap);
+				goto exit;
+			}
+		}
+		ebitmap_destroy(&type_bitmap);
+	} else {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *l_item = op_item->next;
+	struct cil_list_item *r_item = op_item->next->next;
+	
+	enum cil_flavor l_operand = (enum cil_flavor)l_item->data;
+
+	switch (l_operand) {
+	case CIL_CONS_U1:
+		expr->attr = CEXPR_USER;
+		break;
+	case CIL_CONS_U2:
+		expr->attr = CEXPR_USER | CEXPR_TARGET;
+		break;
+	case CIL_CONS_U3:
+		expr->attr = CEXPR_USER | CEXPR_XTARGET;
+		break;
+	case CIL_CONS_R1:
+		expr->attr = CEXPR_ROLE;
+		break;
+	case CIL_CONS_R2:
+		expr->attr = CEXPR_ROLE | CEXPR_TARGET;
+		break;
+	case CIL_CONS_R3:
+		expr->attr = CEXPR_ROLE | CEXPR_XTARGET;
+		break;
+	case CIL_CONS_T1:
+		expr->attr = CEXPR_TYPE;
+		break;
+	case CIL_CONS_T2:
+		expr->attr = CEXPR_TYPE | CEXPR_TARGET;
+		break;
+	case CIL_CONS_T3:
+		expr->attr = CEXPR_TYPE | CEXPR_XTARGET;
+		break;
+	case CIL_CONS_L1: {
+		enum cil_flavor r_operand = (enum cil_flavor)r_item->data;
+
+		if (r_operand == CIL_CONS_L2) {
+			expr->attr = CEXPR_L1L2;
+		} else if (r_operand == CIL_CONS_H1) {
+			expr->attr = CEXPR_L1H1;
+		} else {
+			expr->attr = CEXPR_L1H2;
+		}
+		break;
+	}
+	case CIL_CONS_L2:
+		expr->attr = CEXPR_L2H2;
+		break;
+	case CIL_CONS_H1: {
+		enum cil_flavor r_operand = (enum cil_flavor)r_item->data;
+		if (r_operand == CIL_CONS_L2) {
+			expr->attr = CEXPR_H1L2;
+		} else {
+			expr->attr = CEXPR_H1H2;
+		}
+		break;
+	}
+	default:
+		goto exit;
+		break;
+	}
+
+	if (r_item->flavor == CIL_CONS_OPERAND) {
+		expr->expr_type = CEXPR_ATTR;
+	} else {
+		expr->expr_type = CEXPR_NAMES;
+		if (r_item->flavor == CIL_DATUM) {
+			rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, r_item, expr_flavor, expr);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		} else if (r_item->flavor == CIL_LIST) {
+			struct cil_list *r_expr = r_item->data;
+			struct cil_list_item *curr;
+			cil_list_for_each(curr, r_expr) {
+				rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, curr, expr_flavor, expr);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+		} else {
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *item;
+	enum cil_flavor flavor;
+	constraint_expr_t *op, *h1, *h2, *t1, *t2;
+	int is_leaf = CIL_FALSE;
+
+	if (cil_expr == NULL) {
+		return SEPOL_ERR;
+	}
+
+	item = cil_expr->head;
+	flavor = cil_expr->flavor;
+
+	op = cil_malloc(sizeof(constraint_expr_t));
+	rc = constraint_expr_init(op);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	enum cil_flavor cil_op = (enum cil_flavor)item->data;
+	switch (cil_op) {
+	case CIL_NOT:
+		op->expr_type = CEXPR_NOT;
+		break;
+	case CIL_AND:
+		op->expr_type = CEXPR_AND;
+		break;
+	case CIL_OR:
+		op->expr_type = CEXPR_OR;
+		break;
+	case CIL_EQ:
+		op->op = CEXPR_EQ;
+		is_leaf = CIL_TRUE;
+		break;
+	case CIL_NEQ:
+		op->op = CEXPR_NEQ;
+		is_leaf = CIL_TRUE;
+		break;
+	case CIL_CONS_DOM:
+		op->op = CEXPR_DOM;
+		is_leaf = CIL_TRUE;
+		break;
+	case CIL_CONS_DOMBY:
+		op->op = CEXPR_DOMBY;
+		is_leaf = CIL_TRUE;
+		break;
+	case CIL_CONS_INCOMP:
+		op->op = CEXPR_INCOMP;
+		is_leaf = CIL_TRUE;
+		break;
+	default:
+		goto exit;
+	}
+
+	if (is_leaf == CIL_TRUE) {
+		rc = __cil_constrain_expr_leaf_to_sepol_expr(pdb, db, item, flavor, op);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		*head = op;
+		*tail = op;
+	} else if (cil_op == CIL_NOT) {
+		struct cil_list *l_expr = item->next->data;
+		rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		t1->next = op;
+		*head = h1;
+		*tail = op;
+	} else {
+		struct cil_list *l_expr = item->next->data;
+		struct cil_list *r_expr = item->next->next->data;
+		rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, r_expr, &h2, &t2);
+		if (rc != SEPOL_OK) {
+			constraint_expr_destroy(h1);
+			goto exit;
+		}
+		t1->next = h2;
+		t2->next = op;
+		*head = h1;
+		*tail = op;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	constraint_expr_destroy(op);
+	return SEPOL_ERR;
+}
+
+int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr)
+{
+	int rc;
+	constraint_expr_t *head, *tail;
+
+	rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, cil_expr, &head, &tail);
+	if (rc != SEPOL_OK) {
+		return SEPOL_ERR;
+	}
+
+	*sepol_expr = head;
+
+	return SEPOL_OK;
+}
+
+int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr)
+{
+	int rc = SEPOL_ERR;
+	constraint_node_t *sepol_constrain = NULL;
+	constraint_expr_t *sepol_expr = NULL;
+	class_datum_t *sepol_class = NULL;
+
+	sepol_constrain = cil_malloc(sizeof(*sepol_constrain));
+	memset(sepol_constrain, 0, sizeof(constraint_node_t));
+
+	rc = __cil_get_sepol_class_datum(pdb, class, &sepol_class);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_perms_to_datum(perms, sepol_class, &sepol_constrain->permissions);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	sepol_constrain->expr = sepol_expr;
+	sepol_constrain->next = sepol_class->constraints;
+	sepol_class->constraints = sepol_constrain;
+
+	return SEPOL_OK;
+
+exit:
+	free(sepol_constrain);
+	return rc;
+}
+
+int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				rc = cil_constrain_to_policydb_helper(pdb, db, DATUM(cp->class), cp->perms, expr);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					rc = cil_constrain_expand(pdb, db, cmp->classperms, expr);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}	
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = cil_constrain_expand(pdb, db, cp->classperms, expr);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain)
+{
+	int rc = SEPOL_ERR;
+	rc = cil_constrain_expand(pdb, db, cil_constrain->classperms, cil_constrain->datum_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to insert constraint into policydb\n");
+	return rc;
+}
+
+int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list *expr = cil_validatetrans->datum_expr;
+	class_datum_t *sepol_class = NULL;
+	struct cil_list *class_list;
+	constraint_node_t *sepol_validatetrans = NULL;
+	constraint_expr_t *sepol_expr = NULL;
+	struct cil_list_item *c;
+
+	class_list = cil_expand_class(cil_validatetrans->class);
+
+	cil_list_for_each(c, class_list) {
+		rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+		if (rc != SEPOL_OK) goto exit;
+
+		sepol_validatetrans = cil_malloc(sizeof(*sepol_validatetrans));
+		memset(sepol_validatetrans, 0, sizeof(constraint_node_t));
+
+		rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr);
+		if (rc != SEPOL_OK) {
+			free(sepol_validatetrans);
+			goto exit;
+		}
+		sepol_validatetrans->expr = sepol_expr;
+
+		sepol_validatetrans->next = sepol_class->validatetrans;
+		sepol_class->validatetrans = sepol_validatetrans;
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return rc;
+}
+
+int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t *mls_level)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *i;
+	cat_datum_t *sepol_cat = NULL;
+
+	cil_list_for_each(i, cats->datum_expr) {
+		struct cil_tree_node *node = DATUM(i->data)->nodes->head->data;
+		if (node->flavor == CIL_CATSET) {
+			struct cil_list_item *j;
+			struct cil_catset *cs = i->data;
+			cil_list_for_each(j, cs->cats->datum_expr) {
+				rc = __cil_get_sepol_cat_datum(pdb, j->data, &sepol_cat);
+				if (rc != SEPOL_OK) goto exit;
+
+				rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1);
+				if (rc != SEPOL_OK) goto exit;
+			}
+		} else {
+			rc = __cil_get_sepol_cat_datum(pdb, i->data, &sepol_cat);
+			if (rc != SEPOL_OK) goto exit;
+
+			rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1);
+			if (rc != SEPOL_OK) goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	level_datum_t *sepol_level = NULL;
+	mls_level_t *mls_level = NULL;
+
+	rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level);
+	if (rc != SEPOL_OK) goto exit;
+
+	mls_level = sepol_level->level;
+
+	ebitmap_init(&mls_level->cat);
+
+	if (cil_sens->cats_list) {
+		cil_list_for_each(curr, cil_sens->cats_list) {
+			struct cil_cats *cats = curr->data;
+			rc = __cil_cats_to_mls_level(pdb, cats, mls_level);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n");
+				goto exit;
+			}
+		}
+	}
+
+	sepol_level->defined = 1;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level)
+{
+	int rc = SEPOL_ERR;
+	struct cil_sens *cil_sens = cil_level->sens;
+	struct cil_cats *cats = cil_level->cats;
+	level_datum_t *sepol_level = NULL;
+
+	rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level);
+	if (rc != SEPOL_OK) goto exit;
+
+	mls_level->sens = sepol_level->level->sens;
+
+	ebitmap_init(&mls_level->cat);
+
+	if (cats != NULL) {
+		rc = __cil_cats_to_mls_level(pdb, cats, mls_level);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n");
+			goto exit;
+		}
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
+int __cil_levelrange_to_mls_range(policydb_t *pdb, struct cil_levelrange *cil_lvlrange, mls_range_t *mls_range)
+{
+	int rc = SEPOL_ERR;
+	struct cil_level *low = cil_lvlrange->low;
+	struct cil_level *high = cil_lvlrange->high;
+	mls_level_t *mls_level = NULL;
+
+	mls_level = &mls_range->level[0];
+
+	rc = cil_level_to_mls_level(pdb, low, mls_level);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	mls_level = &mls_range->level[1];
+
+	rc = cil_level_to_mls_level(pdb, high, mls_level);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_userlevel_userrange_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+	int rc = SEPOL_ERR;
+	struct cil_level *cil_level = cil_user->dftlevel;
+	struct cil_levelrange *cil_levelrange = cil_user->range;
+	user_datum_t *sepol_user = NULL;
+
+	rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = cil_level_to_mls_level(pdb, cil_level, &sepol_user->exp_dfltlevel);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_levelrange_to_mls_range(pdb, cil_levelrange, &sepol_user->exp_range);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_context_to_sepol_context(policydb_t *pdb, struct cil_context *cil_context, context_struct_t *sepol_context)
+{
+	int rc = SEPOL_ERR;
+	struct cil_levelrange *cil_lvlrange = cil_context->range;
+	user_datum_t *sepol_user = NULL;
+	role_datum_t *sepol_role = NULL;
+	type_datum_t *sepol_type = NULL;
+
+	rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_context->user), &sepol_user);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_context->role), &sepol_role);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_context->type), &sepol_type);
+	if (rc != SEPOL_OK) goto exit;
+
+	sepol_context->user = sepol_user->s.value;
+	sepol_context->role = sepol_role->s.value;
+	sepol_context->type = sepol_type->s.value;
+
+	if (pdb->mls == CIL_TRUE) {
+		mls_context_init(sepol_context);
+
+		rc = __cil_levelrange_to_mls_range(pdb, cil_lvlrange, &sepol_context->range);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR,"Problem with MLS\n");
+			mls_context_destroy(sepol_context);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_sidorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	unsigned count = 0;
+	ocontext_t *tail = NULL;
+
+	if (db->sidorder == NULL || db->sidorder->head == NULL) {
+		cil_log(CIL_WARN, "No sidorder statement in policy\n");
+		return SEPOL_OK;
+	}
+
+	cil_list_for_each(curr, db->sidorder) {
+		struct cil_sid *cil_sid = (struct cil_sid*)curr->data;
+		struct cil_context *cil_context = cil_sid->context;
+
+		if (cil_context != NULL) {
+			ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_ISID], &tail);
+			count++;
+			new_ocon->sid[0] = count;
+			new_ocon->u.name = cil_strdup(cil_sid->datum.fqn);
+			rc = __cil_context_to_sepol_context(pdb, cil_context, &new_ocon->context[0]);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR,"Problem with context for SID %s\n",cil_sid->datum.fqn);
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans, hashtab_t range_trans_table)
+{
+	int rc = SEPOL_ERR;
+	type_datum_t *sepol_src = NULL;
+	type_datum_t *sepol_tgt = NULL;
+	class_datum_t *sepol_class = NULL;
+	struct cil_list *class_list;
+	range_trans_t *new;
+	ebitmap_t src_bitmap, tgt_bitmap;
+	ebitmap_node_t *node1, *node2;
+	unsigned int i, j;
+	struct cil_list_item *c;
+	struct mls_range *o_range = NULL;
+
+	rc = __cil_expand_type(rangetrans->src, &src_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	rc = __cil_expand_type(rangetrans->exec, &tgt_bitmap);
+	if (rc != SEPOL_OK) goto exit;
+
+	class_list = cil_expand_class(rangetrans->obj);
+
+	ebitmap_for_each_bit(&src_bitmap, node1, i) {
+		if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+		if (rc != SEPOL_OK) goto exit;
+
+		ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+			if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+			rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+			if (rc != SEPOL_OK) goto exit;
+
+			cil_list_for_each(c, class_list) {
+				int add = CIL_TRUE;
+				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+				if (rc != SEPOL_OK) goto exit;
+
+				new = cil_malloc(sizeof(*new));
+				memset(new, 0, sizeof(range_trans_t));
+				new->source_type = sepol_src->s.value;
+				new->target_type = sepol_tgt->s.value;
+				new->target_class = sepol_class->s.value;
+				rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, &new->target_range);
+				if (rc != SEPOL_OK) {
+					free(new);
+					goto exit;
+				}
+
+				rc = SEPOL_OK;
+				rc = hashtab_insert(range_trans_table, (hashtab_key_t)new, &(new->target_range));
+				if (rc != SEPOL_OK) {
+					if (rc == SEPOL_EEXIST) {
+						add = CIL_FALSE;
+						o_range = hashtab_search(range_trans_table, (hashtab_key_t)new);
+						if (!mls_range_eq(&new->target_range, o_range)) {
+							cil_log(CIL_ERR, "Conflicting Range transition rules\n");
+						} else {
+							rc = SEPOL_OK;
+						}
+					} else {
+						cil_log(CIL_ERR, "Out of memory\n");
+					}
+				}
+
+				if (add == CIL_TRUE) {
+					new->next = pdb->range_tr;
+					pdb->range_tr = new;
+				} else {
+					mls_range_destroy(&new->target_range);
+					free(new);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}	
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	ebitmap_destroy(&src_bitmap);
+	ebitmap_destroy(&tgt_bitmap);
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return rc;
+}
+
+int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < portcons->count; i++) {
+		struct cil_portcon *cil_portcon = portcons->array[i];
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_PORT], &tail);
+
+		switch (cil_portcon->proto) {
+		case CIL_PROTOCOL_UDP:
+			new_ocon->u.port.protocol = IPPROTO_UDP;
+			break;
+		case CIL_PROTOCOL_TCP:
+			new_ocon->u.port.protocol = IPPROTO_TCP;
+			break;
+		case CIL_PROTOCOL_DCCP:
+			new_ocon->u.port.protocol = IPPROTO_DCCP;
+			break;
+		default:
+			/* should not get here */
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		new_ocon->u.port.low_port = cil_portcon->port_low;
+		new_ocon->u.port.high_port = cil_portcon->port_high;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_portcon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < netifcons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NETIF], &tail);
+		struct cil_netifcon *cil_netifcon = netifcons->array[i];
+
+		new_ocon->u.name = cil_strdup(cil_netifcon->interface_str);
+
+		rc = __cil_context_to_sepol_context(pdb, cil_netifcon->if_context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = __cil_context_to_sepol_context(pdb, cil_netifcon->packet_context, &new_ocon->context[1]);
+		if (rc != SEPOL_OK) {
+			context_destroy(&new_ocon->context[0]);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+	ocontext_t *tail6 = NULL;
+
+	for (i = 0; i < nodecons->count; i++) {
+		ocontext_t *new_ocon = NULL;
+		struct cil_nodecon *cil_nodecon = nodecons->array[i];
+
+		if (cil_nodecon->addr->family == AF_INET) {
+			new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE], &tail);
+			new_ocon->u.node.addr = cil_nodecon->addr->ip.v4.s_addr;
+			new_ocon->u.node.mask = cil_nodecon->mask->ip.v4.s_addr;
+		} else if (cil_nodecon->addr->family == AF_INET6) {
+			new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE6], &tail6);
+			memcpy(new_ocon->u.node6.addr, &cil_nodecon->addr->ip.v6.s6_addr[0], 16);
+			memcpy(new_ocon->u.node6.mask, &cil_nodecon->mask->ip.v6.s6_addr[0], 16);
+		} else {
+			/* should not get here */
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		rc = __cil_context_to_sepol_context(pdb, cil_nodecon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < fsuses->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_FSUSE], &tail);
+		struct cil_fsuse *cil_fsuse = fsuses->array[i];
+
+		new_ocon->u.name = cil_strdup(cil_fsuse->fs_str);
+		new_ocon->v.behavior = cil_fsuse->type;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_fsuse->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	genfs_t *genfs_tail = NULL;
+	ocontext_t *ocon_tail = NULL;
+
+	for (i = 0; i < genfscons->count; i++) {
+		struct cil_genfscon *cil_genfscon = genfscons->array[i];
+		ocontext_t *new_ocon = cil_malloc(sizeof(ocontext_t));
+		memset(new_ocon, 0, sizeof(ocontext_t));
+
+		if (genfs_tail && strcmp(genfs_tail->fstype, cil_genfscon->fs_str) == 0) {
+			ocon_tail->next = new_ocon;
+		} else {
+			genfs_t *new_genfs = cil_malloc(sizeof(genfs_t));
+			memset(new_genfs, 0, sizeof(genfs_t));
+			new_genfs->fstype = cil_strdup(cil_genfscon->fs_str);
+			new_genfs->head = new_ocon;
+
+			if (genfs_tail) {
+				genfs_tail->next = new_genfs;
+			} else {
+				pdb->genfs = new_genfs;
+			}
+			genfs_tail = new_genfs;
+		}
+
+		ocon_tail = new_ocon;
+
+		new_ocon->u.name = cil_strdup(cil_genfscon->path_str);
+
+		rc = __cil_context_to_sepol_context(pdb, cil_genfscon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < pirqcons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PIRQ], &tail);
+		struct cil_pirqcon *cil_pirqcon = pirqcons->array[i];
+
+		new_ocon->u.pirq = cil_pirqcon->pirq;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_pirqcon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < iomemcons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOMEM], &tail);
+		struct cil_iomemcon *cil_iomemcon = iomemcons->array[i];
+
+		new_ocon->u.iomem.low_iomem = cil_iomemcon->iomem_low;
+		new_ocon->u.iomem.high_iomem = cil_iomemcon->iomem_high;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_iomemcon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < ioportcons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOPORT], &tail);
+		struct cil_ioportcon *cil_ioportcon = ioportcons->array[i];
+
+		new_ocon->u.ioport.low_ioport = cil_ioportcon->ioport_low;
+		new_ocon->u.ioport.high_ioport = cil_ioportcon->ioport_high;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_ioportcon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < pcidevicecons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PCIDEVICE], &tail);
+		struct cil_pcidevicecon *cil_pcidevicecon = pcidevicecons->array[i];
+
+		new_ocon->u.device = cil_pcidevicecon->dev;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_pcidevicecon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_devicetreecon_to_policydb(policydb_t *pdb, struct cil_sort *devicetreecons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < devicetreecons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_DEVICETREE], &tail);
+		struct cil_devicetreecon *cil_devicetreecon = devicetreecons->array[i];
+
+		new_ocon->u.name = cil_strdup(cil_devicetreecon->path);
+
+		rc = __cil_context_to_sepol_context(pdb, cil_devicetreecon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def)
+{
+	struct cil_list_item *curr;
+	class_datum_t *sepol_class;
+	struct cil_list *class_list;
+
+	cil_list_for_each(curr, def->class_datums) {
+		struct cil_list_item *c;
+
+		class_list = cil_expand_class(curr->data);
+
+		cil_list_for_each(c, class_list) {
+			int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+			if (rc != SEPOL_OK) goto exit;
+
+			switch (def->flavor) {
+			case CIL_DEFAULTUSER:
+				if (!sepol_class->default_user) { 
+					sepol_class->default_user = def->object;
+				} else if (sepol_class->default_user != (char)def->object) {
+					cil_log(CIL_ERR,"User default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+					goto exit;
+				}
+				break;
+			case CIL_DEFAULTROLE:
+				if (!sepol_class->default_role) { 
+					sepol_class->default_role = def->object;
+				} else if (sepol_class->default_role != (char)def->object) {
+					cil_log(CIL_ERR,"Role default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+					goto exit;
+				}
+				break;
+			case CIL_DEFAULTTYPE:
+				if (!sepol_class->default_type) { 
+					sepol_class->default_type = def->object;
+				} else if (sepol_class->default_type != (char)def->object) {
+					cil_log(CIL_ERR,"Type default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+					goto exit;
+				}
+				break;
+			default:
+				goto exit;
+			}
+		}
+
+		cil_list_destroy(&class_list, CIL_FALSE);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return SEPOL_ERR;
+}
+
+int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def)
+{
+	struct cil_list_item *curr;
+	class_datum_t *sepol_class;
+	struct cil_list *class_list;
+
+	cil_list_for_each(curr, def->class_datums) {
+		struct cil_list_item *c;
+
+		class_list = cil_expand_class(curr->data);
+
+		cil_list_for_each(c, class_list) {
+			int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+			if (rc != SEPOL_OK) goto exit;
+
+			if (!sepol_class->default_range) { 
+				sepol_class->default_range = def->object_range;
+			} else if (sepol_class->default_range != (char)def->object_range) {
+				cil_log(CIL_ERR,"Range default labeling for class %s already specified\n", DATUM(curr->data)->fqn);
+				goto exit;
+			}
+		}
+
+		cil_list_destroy(&class_list, CIL_FALSE);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_list_destroy(&class_list, CIL_FALSE);
+	return SEPOL_ERR;
+}
+
+int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
+{
+	int rc = SEPOL_OK;
+	int pass;
+	struct cil_args_binary *args = extra_args;
+	const struct cil_db *db;
+	policydb_t *pdb;
+	hashtab_t filename_trans_table;
+	hashtab_t range_trans_table;
+	hashtab_t role_trans_table;
+	void **type_value_to_cil;
+
+	db = args->db;
+	pdb = args->pdb;
+	pass = args->pass;
+	filename_trans_table = args->filename_trans_table;
+	range_trans_table = args->range_trans_table;
+	role_trans_table = args->role_trans_table;
+	type_value_to_cil = args->type_value_to_cil;
+
+	if (node->flavor >= CIL_MIN_DECLARATIVE) {
+		if (node != DATUM(node->data)->nodes->head->data) {
+			goto exit;
+		}
+	}
+
+	switch (pass) {
+	case 1:
+		switch (node->flavor) {
+		case CIL_ROLE:
+			rc = cil_role_to_policydb(pdb, node->data);
+			break;
+		case CIL_TYPE:
+			rc = cil_type_to_policydb(pdb, node->data, type_value_to_cil);
+			break;
+		case CIL_TYPEATTRIBUTE:
+			rc = cil_typeattribute_to_policydb(pdb, node->data, type_value_to_cil);
+			break;
+		case CIL_POLICYCAP:
+			rc = cil_policycap_to_policydb(pdb, node->data);
+			break;
+		case CIL_USER:
+			rc = cil_user_to_policydb(pdb, node->data);
+			break;
+		case CIL_BOOL:
+			rc = cil_bool_to_policydb(pdb, node->data);
+			break;
+		case CIL_CATALIAS:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_catalias_to_policydb(pdb, node->data);
+			}
+			break;
+		case CIL_SENS:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_sepol_level_define(pdb, node->data);
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case 2:
+		switch (node->flavor) {
+		case CIL_TYPE:
+			rc = cil_type_bounds_to_policydb(pdb, node->data);
+			break;
+		case CIL_TYPEALIAS:
+			rc = cil_typealias_to_policydb(pdb, node->data);
+			break;
+		case CIL_TYPEPERMISSIVE:
+			rc = cil_typepermissive_to_policydb(pdb, node->data);
+			break;
+		case CIL_TYPEATTRIBUTE:
+			rc = cil_typeattribute_to_bitmap(pdb, db, node->data);
+			break;
+		case CIL_SENSALIAS:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_sensalias_to_policydb(pdb, node->data);
+			}
+			break;
+		case CIL_ROLE:
+			rc = cil_role_bounds_to_policydb(pdb, node->data);
+			if (rc != SEPOL_OK) goto exit;
+			rc = cil_roletype_to_policydb(pdb, db, node->data);
+			break;
+		case CIL_USER:
+			rc = cil_user_bounds_to_policydb(pdb, node->data);
+			if (rc != SEPOL_OK) goto exit;
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_userlevel_userrange_to_policydb(pdb, node->data);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+			rc = cil_userrole_to_policydb(pdb, db, node->data);
+			break;
+		case CIL_TYPE_RULE:
+			rc = cil_type_rule_to_policydb(pdb, db, node->data);
+			break;
+		case CIL_AVRULE:
+		case CIL_AVRULEX: {
+			struct cil_avrule *rule = node->data;
+			if (db->disable_neverallow != CIL_TRUE && rule->rule_kind == CIL_AVRULE_NEVERALLOW) {
+				struct cil_list *neverallows = args->neverallows;
+				cil_list_prepend(neverallows, CIL_LIST_ITEM, node);
+			}
+			break;
+		}
+		case CIL_ROLETRANSITION:
+			rc = cil_roletrans_to_policydb(pdb, db, node->data, role_trans_table);
+			break;
+		case CIL_ROLEATTRIBUTESET:
+		  /*rc = cil_roleattributeset_to_policydb(pdb, node->data);*/
+			break;
+		case CIL_NAMETYPETRANSITION:
+			rc = cil_typetransition_to_policydb(pdb, db, node->data, filename_trans_table);
+			break;
+		case CIL_CONSTRAIN:
+			rc = cil_constrain_to_policydb(pdb, db, node->data);
+			break;
+		case CIL_MLSCONSTRAIN:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_constrain_to_policydb(pdb, db, node->data);
+			}
+			break;
+		case CIL_VALIDATETRANS:
+			rc = cil_validatetrans_to_policydb(pdb, db, node->data);
+			break;
+		case CIL_MLSVALIDATETRANS:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_validatetrans_to_policydb(pdb, db, node->data);
+			}
+			break;
+		case CIL_RANGETRANSITION:
+			if (pdb->mls == CIL_TRUE) {
+				rc = cil_rangetransition_to_policydb(pdb, db, node->data, range_trans_table);
+			}
+			break;
+		case CIL_DEFAULTUSER:
+		case CIL_DEFAULTROLE:
+		case CIL_DEFAULTTYPE:
+			rc = cil_default_to_policydb(pdb, node->data);
+			break;
+		case CIL_DEFAULTRANGE:
+			rc = cil_defaultrange_to_policydb(pdb, node->data);
+			break;
+		default:
+			break;
+		}
+		break;
+	case 3:
+		switch (node->flavor) {
+		case CIL_BOOLEANIF:
+			rc = cil_booleanif_to_policydb(pdb, db, node, filename_trans_table);
+			break;
+		case CIL_AVRULE: {
+				struct cil_avrule *rule = node->data;
+				if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+					rc = cil_avrule_to_policydb(pdb, db, node->data);
+				}
+			}
+			break;
+		case CIL_AVRULEX: {
+				struct cil_avrule *rule = node->data;
+				if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+					rc = cil_avrulex_to_hashtable(pdb, db, node->data, args);
+				}
+			}
+			break;
+		case CIL_ROLEALLOW:
+			rc = cil_roleallow_to_policydb(pdb, db, node->data);
+			break;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+
+exit:
+	if (rc != SEPOL_OK) {
+		cil_tree_log(node, CIL_ERR, "Binary policy creation failed");
+	}
+	return rc;
+}
+
+int __cil_binary_create_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	if (node->flavor == CIL_BLOCK) {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+			rc = SEPOL_OK;
+			goto exit;
+		}
+	} else if (node->flavor == CIL_MACRO) {
+		*finished = CIL_TREE_SKIP_HEAD;
+		rc = SEPOL_OK;
+		goto exit;
+	} else if (node->flavor == CIL_BOOLEANIF) {
+		*finished = CIL_TREE_SKIP_HEAD;
+	}
+
+	rc = __cil_node_to_policydb(node, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_portcon_to_policydb(pdb, db->portcon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_netifcon_to_policydb(pdb, db->netifcon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_nodecon_to_policydb(pdb, db->nodecon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fsuse_to_policydb(pdb, db->fsuse);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_genfscon_to_policydb(pdb, db->genfscon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (db->target_platform == SEPOL_TARGET_XEN) {
+		rc = cil_pirqcon_to_policydb(pdb, db->pirqcon);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_iomemcon_to_policydb(pdb, db->iomemcon);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_ioportcon_to_policydb(pdb, db->ioportcon);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_pcidevicecon_to_policydb(pdb, db->pcidevicecon);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_devicetreecon_to_policydb(pdb, db->devicetreecon);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+	return SEPOL_OK;
+exit:
+	return rc;
+}
+
+int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	common_datum_t *common = (common_datum_t *)datum;
+
+	if (common->s.value < 1 || common->s.value > pdb->p_commons.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_common_val_to_name[common->s.value - 1] = (char *)key;
+
+	return 0;
+}
+
+int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	class_datum_t *class = (class_datum_t *)datum;
+
+	if (class->s.value < 1 || class->s.value > pdb->p_classes.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_class_val_to_name[class->s.value - 1] = (char *)key;
+	pdb->class_val_to_struct[class->s.value - 1] = class;
+
+	return 0;
+}
+
+int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	role_datum_t *role = (role_datum_t *)datum;
+
+	if (role->s.value < 1 || role->s.value > pdb->p_roles.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_role_val_to_name[role->s.value - 1] = (char *)key;
+	pdb->role_val_to_struct[role->s.value - 1] = role;
+
+	return 0;
+}
+
+int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	type_datum_t *type = (type_datum_t *)datum;
+
+	if (type->s.value < 1 || type->s.value > pdb->p_types.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_type_val_to_name[type->s.value - 1] = (char *)key;
+	pdb->type_val_to_struct[type->s.value - 1] = type;
+
+	return 0;
+}
+
+int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	user_datum_t *user = (user_datum_t *)datum;
+
+	if (user->s.value < 1 || user->s.value > pdb->p_users.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_user_val_to_name[user->s.value - 1] = (char *)key;
+	pdb->user_val_to_struct[user->s.value - 1] = user;
+
+	return 0;
+}
+
+int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	cond_bool_datum_t *bool = (cond_bool_datum_t *)datum;
+
+	if (bool->s.value < 1 || bool->s.value > pdb->p_bools.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_bool_val_to_name[bool->s.value - 1] = (char *)key;
+	pdb->bool_val_to_struct[bool->s.value - 1] = bool;
+
+	return 0;
+}
+
+int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	level_datum_t *level = (level_datum_t *)datum;
+
+	if (level->level->sens < 1 || level->level->sens > pdb->p_levels.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_sens_val_to_name[level->level->sens - 1] = (char *)key;
+
+	return 0;
+}
+
+int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	policydb_t *pdb = data;
+	cat_datum_t *cat = (cat_datum_t *)datum;
+
+	if (cat->s.value < 1 || cat->s.value > pdb->p_cats.nprim) {
+		return -EINVAL;
+	}
+	pdb->p_cat_val_to_name[cat->s.value - 1] = (char *)key;
+
+	return 0;
+}
+
+int __cil_policydb_val_arrays_create(policydb_t *policydb)
+{
+	int rc = SEPOL_ERR;
+
+	policydb->p_common_val_to_name = cil_malloc(sizeof(char *) * policydb->p_commons.nprim);
+	rc = hashtab_map(policydb->p_commons.table, &__cil_common_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_class_val_to_name = cil_malloc(sizeof(char *) * policydb->p_classes.nprim);
+	policydb->class_val_to_struct = cil_malloc(sizeof(class_datum_t *) * policydb->p_classes.nprim);
+	rc = hashtab_map(policydb->p_classes.table, &__cil_class_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_role_val_to_name = cil_malloc(sizeof(char *) * policydb->p_roles.nprim);
+	policydb->role_val_to_struct = cil_malloc(sizeof(role_datum_t *) * policydb->p_roles.nprim);
+	rc = hashtab_map(policydb->p_roles.table, &__cil_role_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_type_val_to_name = cil_malloc(sizeof(char *) * policydb->p_types.nprim);
+	policydb->type_val_to_struct = cil_malloc(sizeof(type_datum_t *) * policydb->p_types.nprim);
+	rc = hashtab_map(policydb->p_types.table, &__cil_type_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_user_val_to_name = cil_malloc(sizeof(char *) * policydb->p_users.nprim);
+	policydb->user_val_to_struct = cil_malloc(sizeof(user_datum_t *) * policydb->p_users.nprim);
+	rc = hashtab_map(policydb->p_users.table, &__cil_user_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_bool_val_to_name = cil_malloc(sizeof(char *) * policydb->p_bools.nprim);
+	policydb->bool_val_to_struct = cil_malloc(sizeof(cond_bool_datum_t *) * policydb->p_bools.nprim);
+	rc = hashtab_map(policydb->p_bools.table, &__cil_bool_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_sens_val_to_name = cil_malloc(sizeof(char *) * policydb->p_levels.nprim);
+	rc = hashtab_map(policydb->p_levels.table, &__cil_level_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	policydb->p_cat_val_to_name = cil_malloc(sizeof(char *) * policydb->p_cats.nprim);
+	rc = hashtab_map(policydb->p_cats.table, &__cil_cat_val_array_insert, policydb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+static void __cil_set_conditional_state_and_flags(policydb_t *pdb)
+{
+	cond_node_t *cur;
+
+	for (cur = pdb->cond_list; cur != NULL; cur = cur->next) {
+		int new_state;
+		cond_av_list_t *c;
+
+		new_state = cond_evaluate_expr(pdb, cur->expr);
+
+		cur->cur_state = new_state;
+
+		if (new_state == -1) {
+			cil_log(CIL_WARN, "Expression result was undefined - disabling all rules\n");
+		}
+
+		for (c = cur->true_list; c != NULL; c = c->next) {
+			if (new_state <= 0) {
+				c->node->key.specified &= ~AVTAB_ENABLED;
+			} else {
+				c->node->key.specified |= AVTAB_ENABLED;
+			}
+		}
+
+		for (c = cur->false_list; c != NULL; c = c->next) {
+			if (new_state) { /* -1 or 1 */
+				c->node->key.specified &= ~AVTAB_ENABLED;
+			} else {
+				c->node->key.specified |= AVTAB_ENABLED;
+			}
+		}
+	}
+}
+
+int __cil_policydb_create(const struct cil_db *db, struct sepol_policydb **spdb)
+{
+	int rc;
+	struct policydb *pdb = NULL;
+
+	rc = sepol_policydb_create(spdb);
+	if (rc < 0) {
+		cil_log(CIL_ERR, "Failed to create policy db\n");
+		// spdb could be a dangling pointer at this point, so reset it so
+		// callers of this function don't need to worry about freeing garbage
+		*spdb = NULL;
+		goto exit;
+	}
+
+	pdb = &(*spdb)->p;
+
+	pdb->policy_type = POLICY_KERN;
+	pdb->target_platform = db->target_platform;
+	pdb->policyvers = db->policy_version;
+	pdb->handle_unknown = db->handle_unknown;
+	pdb->mls = db->mls;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int __cil_policydb_init(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+	int rc = SEPOL_ERR;
+
+	// these flags should get set in __cil_policydb_create. However, for
+	// backwards compatability, it is possible that __cil_policydb_create is
+	// never called. So, they must also be set here.
+	pdb->handle_unknown = db->handle_unknown;
+	pdb->mls = db->mls;
+
+	rc = cil_classorder_to_policydb(pdb, db, class_value_to_cil, perm_value_to_cil);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (pdb->mls == CIL_TRUE) {
+		rc = cil_catorder_to_policydb(pdb, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_sensitivityorder_to_policydb(pdb, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = avtab_alloc(&pdb->te_avtab, MAX_AVTAB_SIZE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = avtab_alloc(&pdb->te_cond_avtab, MAX_AVTAB_SIZE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+
+	return rc;
+}
+
+static unsigned int filename_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+	filename_trans_t *k = (filename_trans_t *)key;
+	return ((k->tclass + (k->ttype << 2) +
+				(k->stype << 9)) & (h->size - 1));
+}
+
+static int filename_trans_compare(hashtab_t h
+             __attribute__ ((unused)), hashtab_key_t key1,
+			              hashtab_key_t key2)
+{
+	filename_trans_t *a = (filename_trans_t *)key1;
+	filename_trans_t *b = (filename_trans_t *)key2;
+
+	return a->stype != b->stype || a->ttype != b->ttype || a->tclass != b->tclass || strcmp(a->name, b->name);
+}
+
+static unsigned int range_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+	range_trans_t *k = (range_trans_t *)key;
+	return ((k->target_class + (k->target_type << 2) +
+				(k->source_type << 5)) & (h->size - 1));
+}
+
+static int range_trans_compare(hashtab_t h
+             __attribute__ ((unused)), hashtab_key_t key1,
+			              hashtab_key_t key2)
+{
+	range_trans_t *a = (range_trans_t *)key1;
+	range_trans_t *b = (range_trans_t *)key2;
+
+	return a->source_type != b->source_type || a->target_type != b->target_type || a->target_class != b->target_class;
+}
+
+static unsigned int role_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+	role_trans_t *k = (role_trans_t *)key;
+	return ((k->role + (k->type << 2) +
+				(k->tclass << 5)) & (h->size - 1));
+}
+
+static int role_trans_compare(hashtab_t h
+             __attribute__ ((unused)), hashtab_key_t key1,
+			              hashtab_key_t key2)
+{
+	role_trans_t *a = (role_trans_t *)key1;
+	role_trans_t *b = (role_trans_t *)key2;
+
+	return a->role != b->role || a->type != b->type || a->tclass != b->tclass;
+}
+
+/* Based on MurmurHash3, written by Austin Appleby and placed in the
+ * public domain.
+ */
+static unsigned int avrulex_hash(__attribute__((unused)) hashtab_t h, hashtab_key_t key)
+{
+	avtab_key_t *k = (avtab_key_t *)key;
+
+	static const uint32_t c1 = 0xcc9e2d51;
+	static const uint32_t c2 = 0x1b873593;
+	static const uint32_t r1 = 15;
+	static const uint32_t r2 = 13;
+	static const uint32_t m  = 5;
+	static const uint32_t n  = 0xe6546b64;
+
+	uint32_t hash = 0;
+
+#define mix(input) { \
+	uint32_t v = input; \
+	v *= c1; \
+	v = (v << r1) | (v >> (32 - r1)); \
+	v *= c2; \
+	hash ^= v; \
+	hash = (hash << r2) | (hash >> (32 - r2)); \
+	hash = hash * m + n; \
+}
+
+	mix(k->target_class);
+	mix(k->target_type);
+	mix(k->source_type);
+	mix(k->specified);
+
+#undef mix
+
+	hash ^= hash >> 16;
+	hash *= 0x85ebca6b;
+	hash ^= hash >> 13;
+	hash *= 0xc2b2ae35;
+	hash ^= hash >> 16;
+
+	return hash & (AVRULEX_TABLE_SIZE - 1);
+}
+
+static int avrulex_compare(hashtab_t h
+             __attribute__ ((unused)), hashtab_key_t key1,
+			              hashtab_key_t key2)
+{
+	avtab_key_t *a = (avtab_key_t *)key1;
+	avtab_key_t *b = (avtab_key_t *)key2;
+
+	return a->source_type != b->source_type || a->target_type != b->target_type || a->target_class != b->target_class || a->specified != b->specified;
+}
+
+int cil_binary_create(const struct cil_db *db, sepol_policydb_t **policydb)
+{
+	int rc = SEPOL_ERR;
+	struct sepol_policydb *pdb = NULL;
+
+	rc = __cil_policydb_create(db, &pdb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_binary_create_allocated_pdb(db, pdb);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	*policydb = pdb;
+
+	return SEPOL_OK;
+
+exit:
+	sepol_policydb_free(pdb);
+
+	return rc;
+}
+
+static void __cil_destroy_sepol_class_perms(class_perm_node_t *curr)
+{
+	class_perm_node_t *next;
+
+	while (curr) {
+		next = curr->next;
+		free(curr);
+		curr = next;
+	}
+}
+
+static int __cil_rule_to_sepol_class_perms(policydb_t *pdb, struct cil_list *classperms, class_perm_node_t **sepol_class_perms)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *i;
+	cil_list_for_each(i, classperms) {
+		if (i->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = i->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				class_perm_node_t *cpn = NULL;
+				class_datum_t *sepol_class = NULL;
+				uint32_t data = 0;
+
+				rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class);
+				if (rc != SEPOL_OK) goto exit;
+
+				rc = __cil_perms_to_datum(cp->perms, sepol_class, &data);
+				if (rc != SEPOL_OK) goto exit;
+				if (data == 0) {
+					/* No permissions */
+					return SEPOL_OK;
+				}
+				cpn = cil_malloc(sizeof(class_perm_node_t));
+				cpn->tclass = sepol_class->s.value;
+				cpn->data = data;
+				cpn->next = *sepol_class_perms;
+				*sepol_class_perms = cpn;
+			} else { /* MAP */
+				struct cil_list_item *j = NULL;
+				cil_list_for_each(j, cp->perms) {
+					struct cil_perm *cmp = j->data;
+					rc = __cil_rule_to_sepol_class_perms(pdb, cmp->classperms, sepol_class_perms);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = i->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = __cil_rule_to_sepol_class_perms(pdb, cp->classperms, sepol_class_perms);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_permx_to_sepol_class_perms(policydb_t *pdb, struct cil_permissionx *permx, class_perm_node_t **sepol_class_perms)
+{
+	int rc = SEPOL_OK;
+	struct cil_list *class_list = NULL;
+	struct cil_list_item *c;
+	class_datum_t *sepol_obj = NULL;
+	class_perm_node_t *cpn;
+	uint32_t data = 0;
+	char *perm_str = NULL;
+
+	class_list = cil_expand_class(permx->obj);
+
+	cil_list_for_each(c, class_list) {
+		rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		switch (permx->kind) {
+			case CIL_PERMX_KIND_IOCTL:
+				perm_str = CIL_KEY_IOCTL;
+				break;
+			default:
+				rc = SEPOL_ERR;
+				goto exit;
+		}
+
+		rc = __perm_str_to_datum(perm_str, sepol_obj, &data);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		cpn = cil_malloc(sizeof(*cpn));
+		cpn->tclass = sepol_obj->s.value;
+		cpn->data = data;
+		cpn->next = *sepol_class_perms;
+		*sepol_class_perms = cpn;
+	}
+
+exit:
+	cil_list_destroy(&class_list, CIL_FALSE);
+
+	return rc;
+}
+
+static void __cil_init_sepol_type_set(type_set_t *t)
+{
+	ebitmap_init(&t->types);
+	ebitmap_init(&t->negset);
+	t->flags = 0;
+}
+
+static int __cil_add_sepol_type(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *datum, ebitmap_t *map)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *n = datum->nodes->head->data;
+	type_datum_t *sepol_datum = NULL;
+
+	if (n->flavor == CIL_TYPEATTRIBUTE) {
+		ebitmap_node_t *tnode;
+		unsigned int i;
+		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+		ebitmap_for_each_bit(attr->types, tnode, i) {
+			if (!ebitmap_get_bit(attr->types, i)) continue;
+			datum = DATUM(db->val_to_type[i]);
+			rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum);
+			if (rc != SEPOL_OK) goto exit;
+			ebitmap_set_bit(map, sepol_datum->s.value - 1, 1);
+		}
+	} else {
+		rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum);
+		if (rc != SEPOL_OK) goto exit;
+		ebitmap_set_bit(map, sepol_datum->s.value - 1, 1);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *node)
+{
+	avrule_t *avrule;
+	struct cil_tree_node *source_node;
+	char *source_path;
+	int is_cil;
+
+	avrule = cil_malloc(sizeof(avrule_t));
+	avrule->specified = kind;
+	avrule->flags = 0;
+	__cil_init_sepol_type_set(&avrule->stypes);
+	__cil_init_sepol_type_set(&avrule->ttypes);
+	avrule->perms = NULL;
+	avrule->line = node->line;
+
+	avrule->source_filename = NULL;
+	avrule->source_line = node->line;
+	source_node = cil_tree_get_next_path(node, &source_path, &is_cil);
+	if (source_node) {
+		avrule->source_filename = source_path;
+		if (!is_cil) {
+			avrule->source_line = node->hll_line;
+		}
+	}
+
+	avrule->next = NULL;
+	return avrule;
+}
+
+static void __cil_destroy_sepol_avrules(avrule_t *curr)
+{
+	avrule_t *next;
+
+	while (curr) {
+		next = curr->next;
+		ebitmap_destroy(&curr->stypes.types);
+		ebitmap_destroy(&curr->stypes.negset);
+		ebitmap_destroy(&curr->ttypes.types);
+		ebitmap_destroy(&curr->ttypes.negset);
+		__cil_destroy_sepol_class_perms(curr->perms);
+		free(curr);
+		curr = next;
+	}
+}
+
+static void __cil_print_parents(const char *pad, struct cil_tree_node *n)
+{
+	if (!n) return;
+
+	__cil_print_parents(pad, n->parent);
+
+	if (n->flavor != CIL_SRC_INFO) {
+		cil_tree_log(n, CIL_ERR,"%s%s", pad, cil_node_to_string(n));
+	}
+}
+
+static void __cil_print_classperm(struct cil_list *cp_list)
+{
+	struct cil_list_item *i1, *i2;
+
+	i1 = cp_list->head;
+	if (i1->flavor == CIL_CLASSPERMS) {
+		struct cil_classperms *cp = i1->data;
+		cil_log(CIL_ERR,"(%s (", DATUM(cp->class)->fqn);
+		cil_list_for_each(i2, cp->perms) {
+			cil_log(CIL_ERR,"%s",DATUM(i2->data)->fqn);
+			if (i2 != cp->perms->tail) {
+				cil_log(CIL_ERR," ");
+			} else {
+				cil_log(CIL_ERR,"))");
+			}
+		}
+	} else {
+		struct cil_classperms_set *cp_set = i1->data;
+		cil_log(CIL_ERR,"%s", DATUM(cp_set->set)->fqn);
+	}
+}
+
+static void __cil_print_permissionx(struct cil_permissionx *px)
+{
+	char *kind_str = "";
+	char *expr_str;
+
+	switch (px->kind) {
+		case CIL_PERMX_KIND_IOCTL:
+			kind_str = CIL_KEY_IOCTL;
+			break;
+		default:
+			kind_str = "unknown";
+			break;
+	}
+
+	__cil_expr_to_string(px->expr_str, CIL_PERMISSIONX, &expr_str);
+
+	cil_log(CIL_ERR, "%s %s (%s)", kind_str, DATUM(px->obj)->fqn, expr_str);
+
+	free(expr_str);
+}
+
+static void __cil_print_rule(const char *pad, const char *kind, struct cil_avrule *avrule)
+{
+	cil_log(CIL_ERR,"%s(%s ", pad, kind);
+	cil_log(CIL_ERR,"%s %s ", DATUM(avrule->src)->fqn, DATUM(avrule->tgt)->fqn);
+
+	if (!avrule->is_extended) {
+		__cil_print_classperm(avrule->perms.classperms);
+	} else {
+		cil_log(CIL_ERR, "(");
+		__cil_print_permissionx(avrule->perms.x.permx);
+		cil_log(CIL_ERR, ")");
+	}
+
+	cil_log(CIL_ERR,")\n");
+}
+
+static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc;
+	struct cil_list_item *i2;
+	struct cil_list *matching;
+	struct cil_avrule *cil_rule = node->data;
+	struct cil_avrule target;
+	struct cil_tree_node *n2;
+	struct cil_avrule *r2;
+	char *neverallow_str;
+	char *allow_str;
+	enum cil_flavor avrule_flavor;
+
+	target.rule_kind = CIL_AVRULE_ALLOWED;
+	target.is_extended = cil_rule->is_extended;
+	target.src = cil_rule->src;
+	target.tgt = cil_rule->tgt;
+	target.perms = cil_rule->perms;
+
+	if (!cil_rule->is_extended) {
+		neverallow_str = CIL_KEY_NEVERALLOW;
+		allow_str = CIL_KEY_ALLOW;
+		avrule_flavor = CIL_AVRULE;
+	} else {
+		neverallow_str = CIL_KEY_NEVERALLOWX;
+		allow_str = CIL_KEY_ALLOWX;
+		avrule_flavor = CIL_AVRULEX;
+	}
+	cil_tree_log(node, CIL_ERR, "%s check failed", neverallow_str);
+	__cil_print_rule("  ", neverallow_str, cil_rule);
+	cil_list_init(&matching, CIL_NODE);
+	rc = cil_find_matching_avrule_in_ast(db->ast->root, avrule_flavor, &target, matching, CIL_FALSE);
+	if (rc) {
+		cil_log(CIL_ERR, "Error occurred while checking %s rules\n", neverallow_str);
+		cil_list_destroy(&matching, CIL_FALSE);
+		goto exit;
+	}
+
+	cil_list_for_each(i2, matching) {
+		n2 = i2->data;
+		r2 = n2->data;
+		__cil_print_parents("    ", n2);
+		__cil_print_rule("      ", allow_str, r2);
+	}
+	cil_log(CIL_ERR,"\n");
+	cil_list_destroy(&matching, CIL_FALSE);
+
+exit:
+	return rc;
+}
+
+static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct cil_tree_node *node, int *violation)
+{
+	int rc = SEPOL_OK;
+	struct cil_avrule *cil_rule = node->data;
+	struct cil_symtab_datum *tgt = cil_rule->tgt;
+	uint32_t kind;
+	avrule_t *rule;
+	struct cil_list *xperms = NULL;
+	struct cil_list_item *item;
+
+	if (!cil_rule->is_extended) {
+		kind = AVRULE_NEVERALLOW;
+	} else {
+		kind = AVRULE_XPERMS_NEVERALLOW;
+	}
+
+	rule = __cil_init_sepol_avrule(kind, node);
+	rule->next = NULL;
+
+	rc = __cil_add_sepol_type(pdb, db, cil_rule->src, &rule->stypes.types);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (tgt->fqn == CIL_KEY_SELF) {
+		rule->flags = RULE_SELF;
+	} else {
+		rc = __cil_add_sepol_type(pdb, db, cil_rule->tgt, &rule->ttypes.types);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (!cil_rule->is_extended) {
+		rc = __cil_rule_to_sepol_class_perms(pdb, cil_rule->perms.classperms, &rule->perms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = check_assertion(pdb, rule);
+		if (rc == CIL_TRUE) {
+			*violation = CIL_TRUE;
+			rc = __cil_print_neverallow_failure(db, node);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+
+	} else {
+		rc = __cil_permx_to_sepol_class_perms(pdb, cil_rule->perms.x.permx, &rule->perms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->perms, &xperms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		cil_list_for_each(item, xperms) {
+			rule->xperms = item->data;
+			rc = check_assertion(pdb, rule);
+			if (rc == CIL_TRUE) {
+				*violation = CIL_TRUE;
+				rc = __cil_print_neverallow_failure(db, node);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+		}
+	}
+
+exit:
+	if (xperms != NULL) {
+		cil_list_for_each(item, xperms) {
+			free(item->data);
+			item->data = NULL;
+		}
+		cil_list_destroy(&xperms, CIL_FALSE);
+	}
+
+	rule->xperms = NULL;
+	__cil_destroy_sepol_avrules(rule);
+
+	return rc;
+}
+
+static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struct cil_list *neverallows, int *violation)
+{
+	int rc = SEPOL_OK;
+	struct cil_list_item *item;
+
+	cil_list_for_each(item, neverallows) {
+		rc = cil_check_neverallow(db, pdb, item->data, violation);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+	struct cil_classperms *cp;
+	struct cil_list *cp_list;
+	class_datum_t *sepol_class = pdb->class_val_to_struct[class - 1];
+	unsigned i;
+
+	cil_classperms_init(&cp);
+
+	cp->class = class_value_to_cil[class];
+	if (!cp->class) goto exit;
+
+	cil_list_init(&cp->perms, CIL_PERM);
+	for (i = 0; i < sepol_class->permissions.nprim; i++) {
+		struct cil_perm *perm;
+		if ((data & (1 << i)) == 0) continue;
+		perm = perm_value_to_cil[class][i+1];
+		if (!perm) goto exit;
+		cil_list_append(cp->perms, CIL_PERM, perm);
+	}
+
+	cil_list_init(&cp_list, CIL_CLASSPERMS);
+	cil_list_append(cp_list, CIL_CLASSPERMS, cp);
+
+	return cp_list;
+
+exit:
+	cil_log(CIL_ERR,"Failed to create CIL class-permissions from sepol values\n");
+	return NULL;
+}
+
+static int cil_avrule_from_sepol(policydb_t *pdb, avtab_ptr_t sepol_rule, struct cil_avrule *cil_rule, void *type_value_to_cil[], struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+	int rc = SEPOL_ERR;
+	avtab_key_t *k = &sepol_rule->key;
+	avtab_datum_t *d = &sepol_rule->datum;
+	cil_rule->src = type_value_to_cil[k->source_type];
+	if (!cil_rule->src) goto exit;
+
+	cil_rule->tgt = type_value_to_cil[k->target_type];
+	if (!cil_rule->tgt) goto exit;
+
+	cil_rule->perms.classperms = cil_classperms_from_sepol(pdb, k->target_class, d->data, class_value_to_cil, perm_value_to_cil);
+	if (!cil_rule->perms.classperms) goto exit;
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR,"Failed to create CIL AV rule from sepol values\n");
+	return rc;
+}
+
+static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void *type_value_to_cil, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[], int *violation)
+{
+	int rc = SEPOL_OK;
+	int i;
+
+	for (i = 0; i < db->num_types; i++) {
+		type_datum_t *child;
+		type_datum_t *parent;
+		avtab_ptr_t bad = NULL;
+		int numbad = 0;
+		struct cil_type *t = db->val_to_type[i];
+
+		if (!t->bounds) continue;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(t), &child);
+		if (rc != SEPOL_OK) goto exit;
+
+		rc = __cil_get_sepol_type_datum(pdb, DATUM(t->bounds), &parent);
+		if (rc != SEPOL_OK) goto exit;
+
+		rc = bounds_check_type(NULL, pdb, child->s.value, parent->s.value, &bad, &numbad);
+		if (rc != SEPOL_OK) goto exit;
+
+		if (bad) {
+			avtab_ptr_t cur;
+			struct cil_avrule target;
+			struct cil_tree_node *n1 = NULL;
+
+			*violation = CIL_TRUE;
+
+                        target.is_extended = 0;
+			target.rule_kind = CIL_AVRULE_ALLOWED;
+			target.src_str = NULL;
+			target.tgt_str = NULL;
+
+			cil_log(CIL_ERR, "Child type %s exceeds bounds of parent %s\n",
+				t->datum.fqn, t->bounds->datum.fqn);
+			for (cur = bad; cur; cur = cur->next) {
+				struct cil_list_item *i2;
+				struct cil_list *matching;
+
+				rc = cil_avrule_from_sepol(pdb, cur, &target, type_value_to_cil, class_value_to_cil, perm_value_to_cil);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_ERR, "Failed to convert sepol avrule to CIL\n");
+					goto exit;
+				}
+				__cil_print_rule("  ", "allow", &target);
+				cil_list_init(&matching, CIL_NODE);
+				rc = cil_find_matching_avrule_in_ast(db->ast->root, CIL_AVRULE, &target, matching, CIL_TRUE);
+				if (rc) {
+					cil_log(CIL_ERR, "Error occurred while checking type bounds\n");
+					cil_list_destroy(&matching, CIL_FALSE);
+					cil_list_destroy(&target.perms.classperms, CIL_TRUE);
+					bounds_destroy_bad(bad);
+					goto exit;
+				}
+				cil_list_for_each(i2, matching) {
+					struct cil_tree_node *n2 = i2->data;
+					struct cil_avrule *r2 = n2->data;
+					if (n1 == n2) {
+						cil_log(CIL_ERR, "    <See previous>\n");
+					} else {
+						n1 = n2;
+						__cil_print_parents("    ", n2);
+						__cil_print_rule("      ", "allow", r2);
+					}
+				}
+				cil_list_destroy(&matching, CIL_FALSE);
+				cil_list_destroy(&target.perms.classperms, CIL_TRUE);
+			}
+			bounds_destroy_bad(bad);
+		}
+	}
+
+exit:
+	return rc;
+}
+
+// assumes policydb is already allocated and initialized properly with things
+// like policy type set to kernel and version set appropriately
+int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *policydb)
+{
+	int rc = SEPOL_ERR;
+	int i;
+	struct cil_args_binary extra_args;
+	policydb_t *pdb = &policydb->p;
+	struct cil_list *neverallows = NULL;
+	hashtab_t filename_trans_table = NULL;
+	hashtab_t range_trans_table = NULL;
+	hashtab_t role_trans_table = NULL;
+	hashtab_t avrulex_ioctl_table = NULL;
+	void **type_value_to_cil = NULL;
+	struct cil_class **class_value_to_cil = NULL;
+	struct cil_perm ***perm_value_to_cil = NULL;
+
+	if (db == NULL || policydb == NULL) {
+		if (db == NULL) {
+			cil_log(CIL_ERR,"db == NULL\n");
+		} else if (policydb == NULL) {
+			cil_log(CIL_ERR,"policydb == NULL\n");
+		}
+		return SEPOL_ERR;
+	}
+
+	/* libsepol values start at 1. Just allocate extra memory rather than
+	 * subtract 1 from the sepol value.
+	 */
+	type_value_to_cil = calloc(db->num_types_and_attrs+1, sizeof(*type_value_to_cil));
+	if (!type_value_to_cil) goto exit;
+
+	class_value_to_cil = calloc(db->num_classes+1, sizeof(*class_value_to_cil));
+	if (!class_value_to_cil) goto exit;
+
+	perm_value_to_cil = calloc(db->num_classes+1, sizeof(*perm_value_to_cil));
+	if (!perm_value_to_cil) goto exit;
+	for (i=1; i < db->num_classes+1; i++) {
+		perm_value_to_cil[i] = calloc(PERMS_PER_CLASS+1, sizeof(*perm_value_to_cil[i]));
+		if (!perm_value_to_cil[i]) goto exit;
+	}
+
+	rc = __cil_policydb_init(pdb, db, class_value_to_cil, perm_value_to_cil);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR,"Problem in policydb_init\n");
+		goto exit;
+	}
+
+	filename_trans_table = hashtab_create(filename_trans_hash, filename_trans_compare, FILENAME_TRANS_TABLE_SIZE);
+	if (!filename_trans_table) {
+		cil_log(CIL_INFO, "Failure to create hashtab for filename_trans\n");
+		goto exit;
+	}
+
+	range_trans_table = hashtab_create(range_trans_hash, range_trans_compare, RANGE_TRANS_TABLE_SIZE);
+	if (!range_trans_table) {
+		cil_log(CIL_INFO, "Failure to create hashtab for range_trans\n");
+		goto exit;
+	}
+
+	role_trans_table = hashtab_create(role_trans_hash, role_trans_compare, ROLE_TRANS_TABLE_SIZE);
+	if (!role_trans_table) {
+		cil_log(CIL_INFO, "Failure to create hashtab for role_trans\n");
+		goto exit;
+	}
+
+	avrulex_ioctl_table = hashtab_create(avrulex_hash, avrulex_compare, AVRULEX_TABLE_SIZE);
+	if (!avrulex_ioctl_table) {
+		cil_log(CIL_INFO, "Failure to create hashtab for avrulex\n");
+		goto exit;
+	}
+
+	cil_list_init(&neverallows, CIL_LIST_ITEM);
+
+	extra_args.db = db;
+	extra_args.pdb = pdb;
+	extra_args.neverallows = neverallows;
+	extra_args.filename_trans_table = filename_trans_table;
+	extra_args.range_trans_table = range_trans_table;
+	extra_args.role_trans_table = role_trans_table;
+	extra_args.avrulex_ioctl_table = avrulex_ioctl_table;
+	extra_args.type_value_to_cil = type_value_to_cil;
+
+	for (i = 1; i <= 3; i++) {
+		extra_args.pass = i;
+
+		rc = cil_tree_walk(db->ast->root, __cil_binary_create_helper, NULL, NULL, &extra_args);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failure while walking cil database\n");
+			goto exit;
+		}
+
+		if (i == 1) {
+			rc = __cil_policydb_val_arrays_create(pdb);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failure creating val_to_{struct,name} arrays\n");
+				goto exit;
+			}
+		}
+
+		if (i == 3) {
+			rc = hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_to_policydb, pdb);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failure creating avrulex rules\n");
+				goto exit;
+			}
+		}
+	}
+
+	rc = cil_sidorder_to_policydb(pdb, db);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_contexts_to_policydb(pdb, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failure while inserting cil contexts into sepol policydb\n");
+		goto exit;
+	}
+
+	if (pdb->type_attr_map == NULL) {
+		rc = __cil_typeattr_bitmap_init(pdb);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failure while initializing typeattribute bitmap\n");
+			goto exit;
+		}
+	}
+
+	cond_optimize_lists(pdb->cond_list);
+	__cil_set_conditional_state_and_flags(pdb);
+
+	if (db->disable_neverallow != CIL_TRUE) {
+		int violation = CIL_FALSE;
+		cil_log(CIL_INFO, "Checking Neverallows\n");
+		rc = cil_check_neverallows(db, pdb, neverallows, &violation);
+		if (rc != SEPOL_OK) goto exit;
+
+		cil_log(CIL_INFO, "Checking User Bounds\n");
+		rc = bounds_check_users(NULL, pdb);
+		if (rc) {
+			violation = CIL_TRUE;
+		}
+
+		cil_log(CIL_INFO, "Checking Role Bounds\n");
+		rc = bounds_check_roles(NULL, pdb);
+		if (rc) {
+			violation = CIL_TRUE;
+		}
+
+		cil_log(CIL_INFO, "Checking Type Bounds\n");
+		rc = cil_check_type_bounds(db, pdb, type_value_to_cil, class_value_to_cil, perm_value_to_cil, &violation);
+		if (rc != SEPOL_OK) goto exit;
+
+		if (violation == CIL_TRUE) {
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	hashtab_destroy(filename_trans_table);
+	hashtab_destroy(range_trans_table);
+	hashtab_destroy(role_trans_table);
+	hashtab_destroy(avrulex_ioctl_table);
+	free(type_value_to_cil);
+	free(class_value_to_cil);
+	/* Range is because libsepol values start at 1. */
+	for (i=1; i < db->num_classes+1; i++) {
+		free(perm_value_to_cil[i]);
+	}
+	free(perm_value_to_cil);
+	cil_list_destroy(&neverallows, CIL_FALSE);
+
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_binary.h b/libsepol/cil/src/cil_binary.h
new file mode 100644
index 0000000..c59b1e3
--- /dev/null
+++ b/libsepol/cil/src/cil_binary.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef _CIL_BINARY_H_
+#define _CIL_BINARY_H_
+
+#include <sepol/policydb/policydb.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+/**
+ * Create a binary policydb from the cil db.
+ *
+ * @param[in] db The cil database.
+ * @param[in] pdb The policy database.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_binary_create(const struct cil_db *db, sepol_policydb_t **pdb);
+
+/**
+ * Create a pre allocated binary policydb from the cil db.
+ *
+ * It is assumed that pdb has been allocated and initialzed so that fields such
+ * as policy type and version are set appropriately. It is reccomended that
+ * instead of calling this, one instead calls cil_binary_create, which will
+ * properly allocate and initialize the pdb and then calls this function. This
+ * funcion is used to maintain binary backwards compatability.
+ *
+ * @param[in] db The cil database.
+ * @param[in] pdb The policy database.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *pdb);
+
+/**
+ * Insert cil common structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the common into.
+ * @param[in] datum The cil_common datum.
+ * @param[out] common_out The sepol common to send back.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out);
+
+/**
+ * Insert cil class structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the class into.
+ * @param[in] datum The cil_class datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_class_to_policydb(policydb_t *pdb, struct cil_class *cil_class);
+
+/**
+ * Insert cil role structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role into.
+ * @param[in] datum The cil_role datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role);
+
+/**
+ * Insert cil roletype structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the roletype into.
+ * @param[in] db The cil database
+ * @param[in] datum The cil_roletype datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR otherwise.
+ */
+int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role);
+
+/**
+ * Insert cil type structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the type into.
+ * @param[in] datum The cil_type datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]);
+
+/**
+ * Insert cil typealias structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the typealias into.
+ * @param[in] datum The cil_typealias datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
+
+/**
+ * Insert cil typepermissive structure into sepol policydb.
+ * The function looks up the perviously inserted type and flips the bit
+ * in the permssive types bitmap that corresponds to that type's value.
+ *
+ * @param[in] pdb The policy database to insert the typepermissive into.
+ * @param[in] datum The cil_typepermissive datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm);
+
+/**
+ * Insert cil attribute structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the attribute into.
+ * @param[in] datum The cil_attribute datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]);
+
+/**
+ * Insert cil attribute structure into sepol type->attribute bitmap.
+ * The function calls helper functions to loop over the attributes lists
+ * of types and negative types. If either of the lists contain an attribute,
+ * the helper functions will recurse into the attribute and record the
+ * attribute's types and negative types. There is no minimum depth.
+ *
+ * @param[in] pdb The policy database that contains the type->attribute bitmap.
+ * @param[in] db The cil database
+ * @param[in] node The tree node that contains the cil_attribute.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *cdb, struct cil_typeattribute *cil_attr);
+
+/**
+ * Insert cil policycap structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the policycap into.
+ * @param[in] node The tree node that contains the cil_policycap.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap);
+
+/**
+ * Insert cil user structure into sepol policydb.
+ *
+ * @param[in] pdb THe policy database to insert the user into.
+ * @param[in] node The tree node that contains the cil_user.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user);
+
+/**
+ * Insert cil userrole structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the userrole into.
+ * @param[in] db The cil database
+ * @param[in] datum The cil_user
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR otherwise.
+ */
+int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user);
+
+/**
+ * Insert cil bool structure into sepol policydb.
+ *
+ * @param[in] pdb THe policy database to insert the bool into.
+ * @param[in] datum The cil_bool datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool);
+
+/**
+ * Insert all ordered cil category structures into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the categories into.
+ * @param[in] db The cil database that contains the category order list.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
+
+/**
+ * Insert cil category alias structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the category alias into.
+ * @param[in] datum The cil_catalias datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
+
+/**
+ * Insert the cil sensitivityorder into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the sensitivityorder into.
+ * @param[in] db the cil database that contains the sensitivityorder list.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
+
+/**
+ * Insert cil type rule structure into sepol policydb.  This includes
+ * typetransition, typechange, and typemember.
+ *
+ * @param[in] pdb The policy database to insert the type rule into.
+ * @param[in] datum The cil_type_rule datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule);
+
+/**
+ * Insert cil avrule structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the avrule into.
+ * @param[in] datum The cil_avrule datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule);
+
+/**
+ * Insert cil booleanif structure into sepol policydb.  This populates the
+ * policydb conditional list.  Each conditional node contains an expression
+ * and true/false avtab_ptr lists that point into te_cond_avtab.
+ *
+ * @param[in] pdb The policy database to insert the booleanif into.
+ * @param[in] node The cil_booleanif node.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table);
+
+/**
+ * Insert cil role transition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role transition into.
+ * @param[in] datum The cil_role_trans datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table);
+
+/**
+ * Insert cil role allow structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role allow into.
+ * @param[in] datum The cil_role_allow datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow);
+
+/**
+ * Insert cil file transition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the file transition into.
+ * @param[in] datum The cil_nametypetransition datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, hashtab_t filename_trans_table);
+
+/**
+ * Insert cil constrain/mlsconstrain structure(s) into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the (mls)constrain into.
+ * @param[in] datum The cil_(mls)constrain datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain);
+
+/**
+ * Define sepol level.
+ * Associates the sepol level (sensitivity) with categories.
+ * Looks at the cil_sens structure for a list of cil_cats to 
+ * associate the sensitivity with.
+ * Sets the sepol level as defined in the sepol policy database.
+ *
+ * @param[in] pdb The policy database that holds the sepol level.
+ * @param[in] datum The cil_sens datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens);
+
+/**
+ * Insert cil rangetransition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the rangetransition into.
+ * @param[in] datum The cil_rangetransition datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans, hashtab_t range_trans_table);
+
+/**
+ * Insert cil portcon structure into sepol policydb.
+ * The function is given a structure containing the sorted portcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the portcon into.
+ * @param[in] node The cil_sort structure that contains the sorted portcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons);
+
+/**
+ * Insert cil netifcon structure into sepol policydb.
+ * The function is given a structure containing the sorted netifcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the netifcon into.
+ * @param[in] node The cil_sort structure that contains the sorted netifcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons);
+
+/**
+ * Insert cil nodecon structure into sepol policydb.
+ * The function is given a structure containing the sorted nodecons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the nodecon into.
+ * @param[in] node The cil_sort structure that contains the sorted nodecons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons);
+
+/**
+ * Insert cil fsuse structure into sepol policydb.
+ * The function is given a structure containing the sorted fsuses and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the fsuse into.
+ * @param[in] node The cil_sort structure that contains the sorted fsuses.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses);
+
+/**
+ * Insert cil genfscon structure into sepol policydb.
+ * The function is given a structure containing the sorted genfscons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the genfscon into.
+ * @param[in] node The cil_sort structure that contains the sorted genfscons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons);
+
+/**
+ * Insert cil pirqcon structure into sepol policydb.
+ * The function is given a structure containing the sorted pirqcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the pirqcon into.
+ * @param[in] node The cil_sort structure that contains the sorted pirqcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons);
+
+/**
+ * Insert cil iomemcon structure into sepol policydb.
+ * The function is given a structure containing the sorted iomemcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the iomemcon into.
+ * @param[in] node The cil_sort structure that contains the sorted iomemcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons);
+
+/**
+ * Insert cil ioportcon structure into sepol policydb.
+ * The function is given a structure containing the sorted ioportcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the ioportcon into.
+ * @param[in] node The cil_sort structure that contains the sorted ioportcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons);
+
+/**
+ * Insert cil pcidevicecon structure into sepol policydb.
+ * The function is given a structure containing the sorted pcidevicecons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the pcidevicecon into.
+ * @param[in] node The cil_sort structure that contains the sorted pcidevicecons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons);
+
+/**
+ * Create an mls level using a cil level.
+ * The function is given a structure containing the a cil_level and
+ * outputs a created mls_level_t.
+ *
+ * @param[in] pdb The policy database to use to get sepol level from cil_level's sensitivity.
+ * @param[in] cil_level The cil_level that will be used to create an mls_level_t.
+ * @param[out] mls_level The mls_level that is created.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level);
+
+#endif //_CIL_BINARY_H_
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
new file mode 100644
index 0000000..1505873
--- /dev/null
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -0,0 +1,6297 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_parser.h"
+#include "cil_build_ast.h"
+#include "cil_copy_ast.h"
+#include "cil_verify.h"
+#include "cil_strpool.h"
+
+struct cil_args_build {
+	struct cil_tree_node *ast;
+	struct cil_db *db;
+	struct cil_tree_node *macro;
+	struct cil_tree_node *boolif;
+	struct cil_tree_node *tunif;
+	struct cil_tree_node *in;
+};
+
+int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *curr;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_N_STRINGS,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ 
+	rc = __cil_verify_syntax(current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+ 	}
+
+	cil_list_init(list, flavor);
+
+	for (curr = current; curr != NULL; curr = curr->next) {
+		cil_list_append(*list, CIL_STRING, curr->data);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_gen_node(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor)
+{
+	int rc = SEPOL_ERR;
+	symtab_t *symtab = NULL;
+
+	rc = __cil_verify_name((const char*)key);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_get_symtab(ast_node->parent, &symtab, sflavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = datum;
+	ast_node->flavor = nflavor;
+
+	if (symtab != NULL) {
+		rc = cil_symtab_insert(symtab, (hashtab_key_t)key, datum, ast_node);
+		if (rc == SEPOL_EEXIST) {
+			cil_log(CIL_ERR, "Re-declaration of %s %s\n", 
+				cil_node_to_string(ast_node), key);
+			if (cil_symtab_get_datum(symtab, key, &datum) == SEPOL_OK) {
+				if (sflavor == CIL_SYM_BLOCKS) {
+					struct cil_tree_node *node = datum->nodes->head->data;
+					cil_tree_log(node, CIL_ERR, "Previous declaration");
+				}
+			}
+			goto exit;
+		}
+	}
+
+	if (ast_node->flavor >= CIL_MIN_DECLARATIVE && ast_node->parent->flavor == CIL_MACRO) {
+		struct cil_list_item *item;
+		struct cil_list *param_list = ((struct cil_macro*)ast_node->parent->data)->params;
+		if (param_list != NULL) {
+			cil_list_for_each(item, param_list) {
+				struct cil_param *param = item->data;
+				if (param->flavor == ast_node->flavor) {
+					if (param->str == key) {
+						cil_log(CIL_ERR, "%s %s shadows a macro parameter in macro declaration\n", cil_node_to_string(ast_node), key);
+						rc = SEPOL_ERR;
+						goto exit;
+					}
+				}
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to create node\n");
+	return rc;
+}
+
+void cil_clear_node(struct cil_tree_node *ast_node)
+{
+	if (ast_node == NULL) {
+		return;
+	}
+
+	ast_node->data = NULL;
+	ast_node->flavor = CIL_NONE;
+}
+
+int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_N_LISTS | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_block *block = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_block_init(&block);
+
+	block->is_abstract = is_abstract;
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)block, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_BLOCK);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad block declaration");
+	cil_destroy_block(block);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_block(struct cil_block *block)
+{
+	if (block == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&block->datum);
+	cil_symtab_array_destroy(block->symtab);
+	cil_list_destroy(&block->bi_nodes, CIL_FALSE);
+
+	free(block);
+}
+
+int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_blockinherit *inherit = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_blockinherit_init(&inherit);
+
+	inherit->block_str = parse_current->next->data;
+
+	ast_node->data = inherit;
+	ast_node->flavor = CIL_BLOCKINHERIT;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad blockinherit declaration");
+	cil_destroy_blockinherit(inherit);
+	return rc;
+}
+
+void cil_destroy_blockinherit(struct cil_blockinherit *inherit)
+{
+	if (inherit == NULL) {
+		return;
+	}
+
+	free(inherit);
+}
+
+int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_blockabstract *abstract = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_blockabstract_init(&abstract);
+
+	abstract->block_str = parse_current->next->data;
+
+	ast_node->data = abstract;
+	ast_node->flavor = CIL_BLOCKABSTRACT;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad blockabstract declaration");
+	cil_destroy_blockabstract(abstract);
+	return rc;
+}
+
+void cil_destroy_blockabstract(struct cil_blockabstract *abstract)
+{
+	if (abstract == NULL) {
+		return;
+	}
+
+	free(abstract);
+}
+
+int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_N_LISTS,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_in *in = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_in_init(&in);
+
+	in->block_str = parse_current->next->data;
+
+	ast_node->data = in;
+	ast_node->flavor = CIL_IN;
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad in statement");
+	cil_destroy_in(in);
+	return rc;
+}
+
+void cil_destroy_in(struct cil_in *in)
+{
+	if (in == NULL) {
+		return;
+	}
+
+	cil_symtab_array_destroy(in->symtab);
+
+	free(in);
+}
+
+int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_class *class = NULL;
+	struct cil_tree_node *perms = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_class_init(&class);
+
+	key = parse_current->next->data;
+	if (key == CIL_KEY_UNORDERED) {
+		cil_log(CIL_ERR, "'unordered' keyword is reserved and not a valid class name.\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)class, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_CLASS);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->next != NULL) {
+		perms = parse_current->next->next->cl_head;
+		rc = cil_gen_perm_nodes(db, perms, ast_node, CIL_PERM, &class->num_perms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad class declaration");
+	cil_destroy_class(class);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_class(struct cil_class *class)
+{
+	if (class == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&class->datum);
+	cil_symtab_destroy(&class->perms);
+
+	free(class);
+}
+
+int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_classorder *classorder = NULL;
+	struct cil_list_item *curr = NULL;
+	struct cil_list_item *head = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc !=  SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classorder_init(&classorder);
+
+	rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASSORDER, &classorder->class_list_str);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	head = classorder->class_list_str->head;
+	cil_list_for_each(curr, classorder->class_list_str) {
+		if (curr->data == CIL_KEY_UNORDERED) {
+			if (curr == head && curr->next == NULL) {
+				cil_log(CIL_ERR, "Classorder 'unordered' keyword must be followed by one or more class.\n");
+				rc = SEPOL_ERR;
+				goto exit;
+			} else if (curr != head) {
+				cil_log(CIL_ERR, "Classorder can only use 'unordered' keyword as the first item in the list.\n");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	ast_node->data = classorder;
+	ast_node->flavor = CIL_CLASSORDER;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad classorder declaration");
+	cil_destroy_classorder(classorder);
+	return rc;
+}
+
+void cil_destroy_classorder(struct cil_classorder *classorder)
+{
+	if (classorder == NULL) {
+		return;
+	}
+
+	if (classorder->class_list_str != NULL) {
+		cil_list_destroy(&classorder->class_list_str, 1);
+	}
+
+	free(classorder);
+}
+
+int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
+{
+	char *key = NULL;
+	struct cil_perm *perm = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_perm_init(&perm);
+
+	key = parse_current->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)perm, (hashtab_key_t)key, CIL_SYM_PERMS, flavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	perm->value = *num_perms;
+	(*num_perms)++;
+
+	return SEPOL_OK;
+
+exit:
+	cil_destroy_perm(perm);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_perm(struct cil_perm *perm)
+{
+	if (perm == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&perm->datum);
+	cil_list_destroy(&perm->classperms, CIL_FALSE);
+
+	free(perm);
+}
+
+int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *new_ast = NULL;
+
+	while(current_perm != NULL) {
+		if (current_perm->cl_head != NULL) {
+		
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		cil_tree_node_init(&new_ast);
+		new_ast->parent = ast_node;
+		new_ast->line = current_perm->line;
+		new_ast->hll_line = current_perm->hll_line;
+
+		rc = cil_gen_perm(db, current_perm, new_ast, flavor, num_perms);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		if (ast_node->cl_head == NULL) {
+			ast_node->cl_head = new_ast;
+		} else {
+			ast_node->cl_tail->next = new_ast;
+		}
+		ast_node->cl_tail = new_ast;
+
+		current_perm = current_perm->next;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad permissions\n");
+	return rc;
+}
+
+int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perms)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_N_STRINGS | CIL_SYN_N_LISTS,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	rc = __cil_verify_syntax(start_perm->cl_head, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_expr(start_perm, CIL_PERM, perms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad permission list or expression\n");
+	return rc;
+}
+
+int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classperms_init(cp);
+
+	(*cp)->class_str = parse_current->data;
+
+	rc = cil_fill_perms(parse_current->next, &(*cp)->perm_strs);
+	if (rc != SEPOL_OK) {
+		cil_destroy_classperms(*cp);
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad class-permissions\n");
+	*cp = NULL;
+	return rc;
+}
+
+void cil_destroy_classperms(struct cil_classperms *cp)
+{
+	if (cp == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&cp->perm_strs, CIL_TRUE);
+	cil_list_destroy(&cp->perms, CIL_FALSE);
+
+	free(cp);
+}
+
+void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set)
+{
+	cil_classperms_set_init(cp_set);
+	(*cp_set)->set_str = parse_current->data;
+}
+
+void cil_destroy_classperms_set(struct cil_classperms_set *cp_set)
+{
+	if (cp_set == NULL) {
+		return;
+	}
+
+	free(cp_set);
+}
+
+int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **cp_list)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *curr;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING | CIL_SYN_LIST,
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	if (parse_current == NULL || cp_list == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_init(cp_list, CIL_CLASSPERMS);
+
+	curr = parse_current->cl_head;
+
+	if (curr == NULL) {
+		/* Class-perms form: SET1 */
+		struct cil_classperms_set *new_cp_set;
+		cil_fill_classperms_set(parse_current, &new_cp_set);
+		cil_list_append(*cp_list, CIL_CLASSPERMS_SET, new_cp_set);
+	} else if (curr->cl_head == NULL) {
+		/* Class-perms form: (CLASS1 (PERM1 ...)) */
+		struct cil_classperms *new_cp;
+		rc = cil_fill_classperms(curr, &new_cp);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_append(*cp_list, CIL_CLASSPERMS, new_cp);
+	} else {
+		cil_log(CIL_ERR, "Bad class-permissions list syntax\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Problem filling class-permissions list\n");
+	cil_list_destroy(cp_list, CIL_TRUE);
+	return rc;
+}
+
+void cil_destroy_classperms_list(struct cil_list **cp_list)
+{
+	struct cil_list_item *curr;
+
+	if (cp_list == NULL || *cp_list == NULL) {
+		return;
+	}
+
+	cil_list_for_each(curr, *cp_list) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			cil_destroy_classperms(curr->data);
+		} else {
+			cil_destroy_classperms_set(curr->data);
+		}
+	}
+
+	cil_list_destroy(cp_list, CIL_FALSE);
+}
+
+int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	struct cil_classpermission *cp = NULL;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classpermission_init(&cp);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)cp, (hashtab_key_t)key, CIL_SYM_CLASSPERMSETS, CIL_CLASSPERMISSION);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad classpermission declaration");
+	cil_destroy_classpermission(cp);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_classpermission(struct cil_classpermission *cp)
+{
+	if (cp == NULL) {
+		return;
+	}
+
+	if (cp->datum.name != NULL) {
+		cil_list_destroy(&cp->classperms, CIL_FALSE);
+	} else {
+		/* anonymous classpermission from call */
+		cil_destroy_classperms_list(&cp->classperms);
+	}
+
+	cil_symtab_datum_destroy(&cp->datum);
+
+
+	free(cp);
+}
+
+int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_classpermissionset *cps = NULL;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classpermissionset_init(&cps);
+
+	cps->set_str = parse_current->next->data;
+
+	rc = cil_fill_classperms_list(parse_current->next->next, &cps->classperms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = cps;
+	ast_node->flavor = CIL_CLASSPERMISSIONSET;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad classpermissionset");
+	cil_destroy_classpermissionset(cps);
+	return rc;
+}
+
+void cil_destroy_classpermissionset(struct cil_classpermissionset *cps)
+{
+	if (cps == NULL) {
+		return;
+	}
+
+	cil_destroy_classperms_list(&cps->classperms);
+
+	free(cps);
+}
+
+int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_class *map = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_class_init(&map);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)map, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_MAP_CLASS);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_MAP_PERM, &map->num_perms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad map class declaration");
+	cil_destroy_class(map);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_classmapping *mapping = NULL;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classmapping_init(&mapping);
+
+	mapping->map_class_str = parse_current->next->data;
+	mapping->map_perm_str = parse_current->next->next->data;
+
+	rc = cil_fill_classperms_list(parse_current->next->next->next, &mapping->classperms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = mapping;
+	ast_node->flavor = CIL_CLASSMAPPING;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad classmapping declaration");
+	cil_destroy_classmapping(mapping);
+	return rc;
+}
+
+void cil_destroy_classmapping(struct cil_classmapping *mapping)
+{
+	if (mapping == NULL) {
+		return;
+	}
+
+	cil_destroy_classperms_list(&mapping->classperms);
+
+	free(mapping);
+}
+
+// TODO try to merge some of this with cil_gen_class (helper function for both)
+int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_class *common = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_class_init(&common);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)common, (hashtab_key_t)key, CIL_SYM_COMMONS, CIL_COMMON);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_PERM, &common->num_perms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad common declaration");
+	cil_destroy_class(common);
+	cil_clear_node(ast_node);
+	return rc;
+
+}
+
+int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_classcommon *clscom = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_classcommon_init(&clscom);
+
+	clscom->class_str = parse_current->next->data;
+	clscom->common_str = parse_current->next->next->data;
+
+	ast_node->data = clscom;
+	ast_node->flavor = CIL_CLASSCOMMON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad classcommon declaration");
+	cil_destroy_classcommon(clscom);
+	return rc;
+
+}
+
+void cil_destroy_classcommon(struct cil_classcommon *clscom)
+{
+	if (clscom == NULL) {
+		return;
+	}
+
+	free(clscom);
+}
+
+int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_sid *sid = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_sid_init(&sid);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sid, (hashtab_key_t)key, CIL_SYM_SIDS, CIL_SID);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sid declaration");
+	cil_destroy_sid(sid);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_sid(struct cil_sid *sid)
+{
+	if (sid == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&sid->datum);
+	free(sid);
+}
+
+int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_sidcontext *sidcon = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_sidcontext_init(&sidcon);
+
+	sidcon->sid_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		sidcon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&sidcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, sidcon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = sidcon;
+	ast_node->flavor = CIL_SIDCONTEXT;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sidcontext declaration");
+	cil_destroy_sidcontext(sidcon);
+	return rc;
+}
+
+void cil_destroy_sidcontext(struct cil_sidcontext *sidcon)
+{
+	if (sidcon == NULL) {
+		return;
+	}
+
+	if (sidcon->context_str == NULL && sidcon->context != NULL) {
+		cil_destroy_context(sidcon->context);
+	}
+
+	free(sidcon);
+}
+
+int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_sidorder *sidorder = NULL;
+	struct cil_list_item *curr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc !=  SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_sidorder_init(&sidorder);
+
+	rc = cil_fill_list(parse_current->next->cl_head, CIL_SIDORDER, &sidorder->sid_list_str);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_for_each(curr, sidorder->sid_list_str) {
+		if (curr->data == CIL_KEY_UNORDERED) {
+			cil_log(CIL_ERR, "Sidorder cannot be unordered.\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	ast_node->data = sidorder;
+	ast_node->flavor = CIL_SIDORDER;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sidorder declaration");
+	cil_destroy_sidorder(sidorder);
+	return rc;
+}
+
+void cil_destroy_sidorder(struct cil_sidorder *sidorder)
+{
+	if (sidorder == NULL) {
+		return;
+	}
+
+	if (sidorder->sid_list_str != NULL) {
+		cil_list_destroy(&sidorder->sid_list_str, 1);
+	}
+
+	free(sidorder);
+}
+
+int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_user *user = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_user_init(&user);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)user, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USER);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad user declaration");
+	cil_destroy_user(user);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_user(struct cil_user *user)
+{
+	if (user == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&user->datum);
+	ebitmap_destroy(user->roles);
+	free(user->roles);
+	free(user);
+}
+
+int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_userattribute *attr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userattribute_init(&attr);
+
+	key = parse_current->next->data;
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USERATTRIBUTE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userattribute declaration");
+	cil_destroy_userattribute(attr);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_userattribute(struct cil_userattribute *attr)
+{
+	struct cil_list_item *expr = NULL;
+	struct cil_list_item *next = NULL;
+
+	if (attr == NULL) {
+		return;
+	}
+
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		expr = attr->expr_list->head;
+		while (expr != NULL) {
+			next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+
+	cil_symtab_datum_destroy(&attr->datum);
+	ebitmap_destroy(attr->users);
+	free(attr->users);
+	free(attr);
+}
+
+int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_userattributeset *attrset = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userattributeset_init(&attrset);
+
+	attrset->attr_str = parse_current->next->data;
+
+	rc = cil_gen_expr(parse_current->next->next, CIL_USER, &attrset->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	ast_node->data = attrset;
+	ast_node->flavor = CIL_USERATTRIBUTESET;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userattributeset declaration");
+	cil_destroy_userattributeset(attrset);
+
+	return rc;
+}
+
+void cil_destroy_userattributeset(struct cil_userattributeset *attrset)
+{
+	if (attrset == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+	cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+	free(attrset);
+}
+
+int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_userlevel *usrlvl = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userlevel_init(&usrlvl);
+
+	usrlvl->user_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		usrlvl->level_str = parse_current->next->next->data;
+	} else {
+		cil_level_init(&usrlvl->level);
+
+		rc = cil_fill_level(parse_current->next->next->cl_head, usrlvl->level);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = usrlvl;
+	ast_node->flavor = CIL_USERLEVEL;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userlevel declaration");
+	cil_destroy_userlevel(usrlvl);
+	return rc;
+}
+
+void cil_destroy_userlevel(struct cil_userlevel *usrlvl)
+{
+	if (usrlvl == NULL) {
+		return;
+	}
+
+	if (usrlvl->level_str == NULL && usrlvl->level != NULL) {
+		cil_destroy_level(usrlvl->level);
+	}
+
+	free(usrlvl);
+}
+
+int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_userrange *userrange = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userrange_init(&userrange);
+
+	userrange->user_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		userrange->range_str = parse_current->next->next->data;
+	} else {
+		cil_levelrange_init(&userrange->range);
+
+		rc = cil_fill_levelrange(parse_current->next->next->cl_head, userrange->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = userrange;
+	ast_node->flavor = CIL_USERRANGE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userrange declaration");
+	cil_destroy_userrange(userrange);
+	return rc;
+}
+
+void cil_destroy_userrange(struct cil_userrange *userrange)
+{
+	if (userrange == NULL) {
+		return;
+	}
+
+	if (userrange->range_str == NULL && userrange->range != NULL) {
+		cil_destroy_levelrange(userrange->range);
+	}
+
+	free(userrange);
+}
+
+int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_userprefix *userprefix = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userprefix_init(&userprefix);
+
+	userprefix->user_str = parse_current->next->data;
+	userprefix->prefix_str = parse_current->next->next->data;
+
+	ast_node->data = userprefix;
+	ast_node->flavor = CIL_USERPREFIX;
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userprefix declaration");
+	cil_destroy_userprefix(userprefix);
+	return rc;
+}
+
+void cil_destroy_userprefix(struct cil_userprefix *userprefix)
+{
+	if (userprefix == NULL) {
+		return;
+	}
+
+	free(userprefix);
+}
+
+int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_selinuxuser *selinuxuser = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_selinuxuser_init(&selinuxuser);
+
+	selinuxuser->name_str = parse_current->next->data;
+	selinuxuser->user_str = parse_current->next->next->data;
+
+	if (parse_current->next->next->next->cl_head == NULL) {
+		selinuxuser->range_str = parse_current->next->next->next->data;
+	} else {
+		cil_levelrange_init(&selinuxuser->range);
+
+		rc = cil_fill_levelrange(parse_current->next->next->next->cl_head, selinuxuser->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = selinuxuser;
+	ast_node->flavor = CIL_SELINUXUSER;
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuser declaration");
+	cil_destroy_selinuxuser(selinuxuser);
+	return rc;
+}
+
+int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_selinuxuser *selinuxuser = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_selinuxuser_init(&selinuxuser);
+
+	selinuxuser->name_str = cil_strpool_add("__default__");
+	selinuxuser->user_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		selinuxuser->range_str = parse_current->next->next->data;
+	} else {
+		cil_levelrange_init(&selinuxuser->range);
+
+		rc = cil_fill_levelrange(parse_current->next->next->cl_head, selinuxuser->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = selinuxuser;
+	ast_node->flavor = CIL_SELINUXUSERDEFAULT;
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuserdefault declaration");
+	cil_destroy_selinuxuser(selinuxuser);
+	return rc;
+}
+
+void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser)
+{
+	if (selinuxuser == NULL) {
+		return;
+	}
+
+	if (selinuxuser->range_str == NULL && selinuxuser->range != NULL) {
+		cil_destroy_levelrange(selinuxuser->range);
+	}
+
+	free(selinuxuser);
+}
+
+int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_role *role = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_role_init(&role);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)role, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad role declaration");
+	cil_destroy_role(role);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_role(struct cil_role *role)
+{
+	if (role == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&role->datum);
+	ebitmap_destroy(role->types);
+	free(role->types);
+	free(role);
+}
+
+int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_roletype *roletype = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_roletype_init(&roletype);
+
+	roletype->role_str = parse_current->next->data;
+	roletype->type_str = parse_current->next->next->data;
+
+	ast_node->data = roletype;
+	ast_node->flavor = CIL_ROLETYPE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad roletype declaration");
+	cil_destroy_roletype(roletype);
+	return rc;
+}
+
+void cil_destroy_roletype(struct cil_roletype *roletype)
+{
+	if (roletype == NULL) {
+		return;
+	}
+
+	free(roletype);
+}
+
+int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_userrole *userrole = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_userrole_init(&userrole);
+
+	userrole->user_str = parse_current->next->data;
+	userrole->role_str = parse_current->next->next->data;
+
+	ast_node->data = userrole;
+	ast_node->flavor = CIL_USERROLE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad userrole declaration");
+	cil_destroy_userrole(userrole);
+	return rc;
+}
+
+void cil_destroy_userrole(struct cil_userrole *userrole)
+{
+	if (userrole == NULL) {
+		return;
+	}
+
+	free(userrole);
+}
+
+int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_roletransition *roletrans = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_roletransition_init(&roletrans);
+
+	roletrans->src_str = parse_current->next->data;
+	roletrans->tgt_str = parse_current->next->next->data;
+	roletrans->obj_str = parse_current->next->next->next->data;
+	roletrans->result_str = parse_current->next->next->next->next->data;
+
+	ast_node->data = roletrans;
+	ast_node->flavor = CIL_ROLETRANSITION;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad roletransition rule");
+	cil_destroy_roletransition(roletrans);
+	return rc;
+}
+
+void cil_destroy_roletransition(struct cil_roletransition *roletrans)
+{
+	if (roletrans == NULL) {
+		return;
+	}
+
+	free(roletrans);
+}
+
+int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_roleallow *roleallow = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_roleallow_init(&roleallow);
+
+	roleallow->src_str = parse_current->next->data;
+	roleallow->tgt_str = parse_current->next->next->data;
+
+	ast_node->data = roleallow;
+	ast_node->flavor = CIL_ROLEALLOW;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad roleallow rule");
+	cil_destroy_roleallow(roleallow);
+	return rc;
+}
+
+void cil_destroy_roleallow(struct cil_roleallow *roleallow)
+{
+	if (roleallow == NULL) {
+		return;
+	}
+
+	free(roleallow);
+}
+
+int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_roleattribute *attr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->data == CIL_KEY_SELF) {
+		cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_roleattribute_init(&attr);
+
+	key = parse_current->next->data;
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLEATTRIBUTE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad roleattribute declaration");
+	cil_destroy_roleattribute(attr);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_roleattribute(struct cil_roleattribute *attr)
+{
+	if (attr == NULL) {
+		return;
+	}
+
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		struct cil_list_item *expr = attr->expr_list->head;
+		while (expr != NULL) {
+			struct cil_list_item *next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+
+	cil_symtab_datum_destroy(&attr->datum);
+	ebitmap_destroy(attr->roles);
+	free(attr->roles);
+	free(attr);
+}
+
+int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_roleattributeset *attrset = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_roleattributeset_init(&attrset);
+
+	attrset->attr_str = parse_current->next->data;
+
+	rc = cil_gen_expr(parse_current->next->next, CIL_ROLE, &attrset->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	ast_node->data = attrset;
+	ast_node->flavor = CIL_ROLEATTRIBUTESET;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad roleattributeset declaration");
+	cil_destroy_roleattributeset(attrset);
+
+	return rc;
+}
+
+void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset)
+{
+	if (attrset == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+	cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+	free(attrset);
+}
+
+int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_avrule *rule = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_avrule_init(&rule);
+
+	rule->is_extended = 0;
+	rule->rule_kind = rule_kind;
+
+	rule->src_str = parse_current->next->data;
+	rule->tgt_str = parse_current->next->next->data;
+
+	rc = cil_fill_classperms_list(parse_current->next->next->next, &rule->perms.classperms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = rule;
+	ast_node->flavor = CIL_AVRULE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad allow rule");
+	cil_destroy_avrule(rule);
+	return rc;
+}
+
+void cil_destroy_avrule(struct cil_avrule *rule)
+{
+	if (rule == NULL) {
+		return;
+	}
+
+	if (!rule->is_extended) {
+		cil_destroy_classperms_list(&rule->perms.classperms);
+	} else {
+		if (rule->perms.x.permx_str == NULL && rule->perms.x.permx != NULL) {
+			cil_destroy_permissionx(rule->perms.x.permx);
+		}
+	}
+
+	free(rule);
+}
+
+int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->data == CIL_KEY_IOCTL) {
+		permx->kind = CIL_PERMX_KIND_IOCTL;
+	} else {
+		cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	permx->obj_str = parse_current->next->data;
+
+	rc = cil_gen_expr(parse_current->next->next, CIL_PERMISSIONX, &permx->expr_str);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad permissionx content");
+	return rc;
+}
+
+int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_permissionx *permx = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_permissionx_init(&permx);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)permx, (hashtab_key_t)key, CIL_SYM_PERMX, CIL_PERMISSIONX);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fill_permissionx(parse_current->next->next->cl_head, permx);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad permissionx statement");
+	cil_destroy_permissionx(permx);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_permissionx(struct cil_permissionx *permx)
+{
+	if (permx == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&permx->datum);
+
+	cil_list_destroy(&permx->expr_str, CIL_TRUE);
+	ebitmap_destroy(permx->perms);
+	free(permx->perms);
+	free(permx);
+}
+
+int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_avrule *rule = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_avrule_init(&rule);
+
+	rule->is_extended = 1;
+	rule->rule_kind = rule_kind;
+	rule->src_str = parse_current->next->data;
+	rule->tgt_str = parse_current->next->next->data;
+
+	if (parse_current->next->next->next->cl_head == NULL) {
+		rule->perms.x.permx_str = parse_current->next->next->next->data;
+	} else {
+		cil_permissionx_init(&rule->perms.x.permx);
+
+		rc = cil_fill_permissionx(parse_current->next->next->next->cl_head, rule->perms.x.permx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = rule;
+	ast_node->flavor = CIL_AVRULEX;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad allowx rule");
+	cil_destroy_avrule(rule);
+	return rc;
+}
+
+int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_type_rule *rule = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_type_rule_init(&rule);
+
+	rule->rule_kind = rule_kind;
+	rule->src_str = parse_current->next->data;
+	rule->tgt_str = parse_current->next->next->data;
+	rule->obj_str = parse_current->next->next->next->data;
+	rule->result_str = parse_current->next->next->next->next->data;
+
+	ast_node->data = rule;
+	ast_node->flavor = CIL_TYPE_RULE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad type rule");
+	cil_destroy_type_rule(rule);
+	return rc;
+}
+
+void cil_destroy_type_rule(struct cil_type_rule *rule)
+{
+	if (rule == NULL) {
+		return;
+	}
+
+	free(rule);
+}
+
+int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_type *type = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->data == CIL_KEY_SELF) {
+		cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_type_init(&type);
+
+	key = parse_current->next->data;
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)type, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad type declaration");
+	cil_destroy_type(type);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_type(struct cil_type *type)
+{
+	if (type == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&type->datum);
+	free(type);
+}
+
+int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_typeattribute *attr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->data == CIL_KEY_SELF) {
+		cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_typeattribute_init(&attr);
+
+	key = parse_current->next->data;
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad typeattribute declaration");
+	cil_destroy_typeattribute(attr);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_typeattribute(struct cil_typeattribute *attr)
+{
+	if (attr == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&attr->datum);
+
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		struct cil_list_item *expr = attr->expr_list->head;
+		while (expr != NULL) {
+			struct cil_list_item *next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+	ebitmap_destroy(attr->types);
+	free(attr->types);
+	free(attr);
+}
+
+int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_bool *boolean = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_bool_init(&boolean);
+
+	key = parse_current->next->data;
+
+	if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
+		boolean->value = CIL_TRUE;
+	} else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
+		boolean->value = CIL_FALSE;
+	} else {
+		cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)boolean, (hashtab_key_t)key, CIL_SYM_BOOLS, CIL_BOOL);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	if (tunableif) {
+		cil_tree_log(parse_current, CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration");
+	} else {
+		cil_tree_log(parse_current, CIL_ERR, "Bad boolean declaration");
+	}
+	cil_destroy_bool(boolean);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_bool(struct cil_bool *boolean)
+{
+	if (boolean == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&boolean->datum);
+	free(boolean);
+}
+
+int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_tunable *tunable = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_tunable_init(&tunable);
+
+	key = parse_current->next->data;
+
+	if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
+		tunable->value = CIL_TRUE;
+	} else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
+		tunable->value = CIL_FALSE;
+	} else {
+		cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)tunable, (hashtab_key_t)key, CIL_SYM_TUNABLES, CIL_TUNABLE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad tunable declaration");
+	cil_destroy_tunable(tunable);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_tunable(struct cil_tunable *tunable)
+{
+	if (tunable == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&tunable->datum);
+	free(tunable);
+}
+
+static enum cil_flavor __cil_get_expr_operator_flavor(const char *op)
+{
+	if (op == NULL) return CIL_NONE;
+	else if (op == CIL_KEY_AND)   return CIL_AND;
+	else if (op == CIL_KEY_OR)    return CIL_OR;
+	else if (op == CIL_KEY_NOT)   return CIL_NOT;
+	else if (op == CIL_KEY_EQ)    return CIL_EQ;    /* Only conditional */
+	else if (op == CIL_KEY_NEQ)   return CIL_NEQ;   /* Only conditional */
+	else if (op == CIL_KEY_XOR)   return CIL_XOR;
+	else if (op == CIL_KEY_ALL)   return CIL_ALL;   /* Only set and permissionx */
+	else if (op == CIL_KEY_RANGE) return CIL_RANGE; /* Only catset and permissionx */
+	else return CIL_NONE;
+}
+
+static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth);
+
+static int __cil_fill_expr_helper(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
+{
+	int rc = SEPOL_ERR;
+	enum cil_flavor op;
+
+	if (flavor == CIL_BOOL && *depth > COND_EXPR_MAXDEPTH) {
+		cil_log(CIL_ERR, "Max depth of %d exceeded for boolean expression\n", COND_EXPR_MAXDEPTH);
+		goto exit;
+	}
+
+	op = __cil_get_expr_operator_flavor(current->data);
+
+	rc = cil_verify_expr_syntax(current, op, flavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (op != CIL_NONE) {
+		cil_list_append(expr, CIL_OP, (void *)op);
+		current = current->next;
+	}
+
+	if (op == CIL_NONE || op == CIL_ALL) {
+		(*depth)++;
+	}
+
+	for (;current != NULL; current = current->next) {
+		rc = __cil_fill_expr(current, flavor, expr, depth);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	(*depth)--;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
+{
+	int rc = SEPOL_ERR;
+
+	if (current->cl_head == NULL) {
+		enum cil_flavor op = __cil_get_expr_operator_flavor(current->data);
+		if (op != CIL_NONE) {
+			cil_log(CIL_ERR, "Operator (%s) not in an expression\n", (char*)current->data);
+			goto exit;
+		}
+		cil_list_append(expr, CIL_STRING, current->data);
+	} else {
+		struct cil_list *sub_expr;
+		cil_list_init(&sub_expr, flavor);
+		rc = __cil_fill_expr_helper(current->cl_head, flavor, sub_expr, depth);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_append(expr, CIL_LIST, sub_expr);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
+{
+	int rc = SEPOL_ERR;
+	int depth = 0;
+
+	cil_list_init(expr, flavor);
+
+	if (current->cl_head == NULL) {
+		rc = __cil_fill_expr(current, flavor, *expr, &depth);
+	} else {
+		rc = __cil_fill_expr_helper(current->cl_head, flavor, *expr, &depth);
+	}
+
+	if (rc != SEPOL_OK) {
+		cil_list_destroy(expr, CIL_TRUE);
+		cil_log(CIL_ERR, "Bad expression\n");
+	}
+
+	return rc;
+}
+
+static enum cil_flavor __cil_get_constraint_operator_flavor(const char *op)
+{
+	if (op == CIL_KEY_AND)         return CIL_AND;
+	else if (op == CIL_KEY_OR)     return CIL_OR;
+	else if (op == CIL_KEY_NOT)    return CIL_NOT;
+	else if (op == CIL_KEY_EQ)     return CIL_EQ;
+	else if (op == CIL_KEY_NEQ)    return CIL_NEQ;
+	else if (op == CIL_KEY_CONS_DOM)    return CIL_CONS_DOM;
+	else if (op == CIL_KEY_CONS_DOMBY)  return CIL_CONS_DOMBY;
+	else if (op == CIL_KEY_CONS_INCOMP) return CIL_CONS_INCOMP;
+	else return CIL_NONE;
+}
+
+static enum cil_flavor __cil_get_constraint_operand_flavor(const char *operand)
+{
+	if (operand == NULL) return CIL_LIST;
+	else if (operand == CIL_KEY_CONS_T1) return CIL_CONS_T1;
+	else if (operand == CIL_KEY_CONS_T2) return CIL_CONS_T2;
+	else if (operand == CIL_KEY_CONS_T3) return CIL_CONS_T3;
+	else if (operand == CIL_KEY_CONS_R1) return CIL_CONS_R1;
+	else if (operand == CIL_KEY_CONS_R2) return CIL_CONS_R2;
+	else if (operand == CIL_KEY_CONS_R3) return CIL_CONS_R3;
+	else if (operand == CIL_KEY_CONS_U1) return CIL_CONS_U1;
+	else if (operand == CIL_KEY_CONS_U2) return CIL_CONS_U2;
+	else if (operand == CIL_KEY_CONS_U3) return CIL_CONS_U3;
+	else if (operand == CIL_KEY_CONS_L1) return CIL_CONS_L1;
+	else if (operand == CIL_KEY_CONS_L2) return CIL_CONS_L2;
+	else if (operand == CIL_KEY_CONS_H1) return CIL_CONS_H1;
+	else if (operand == CIL_KEY_CONS_H2) return CIL_CONS_H2;
+	else return CIL_STRING;
+}
+
+static int __cil_fill_constraint_leaf_expr(struct cil_tree_node *current, enum cil_flavor expr_flavor, enum cil_flavor op, struct cil_list **leaf_expr)
+{
+	int rc = SEPOL_ERR;
+	enum cil_flavor leaf_expr_flavor = CIL_NONE;
+	enum cil_flavor l_flavor = CIL_NONE;
+	enum cil_flavor r_flavor = CIL_NONE;
+
+	l_flavor = __cil_get_constraint_operand_flavor(current->next->data);
+	r_flavor = __cil_get_constraint_operand_flavor(current->next->next->data);
+
+	switch (l_flavor) {
+	case CIL_CONS_U1:
+	case CIL_CONS_U2:
+	case CIL_CONS_U3:
+		leaf_expr_flavor = CIL_USER;
+		break;
+	case CIL_CONS_R1:
+	case CIL_CONS_R2:
+	case CIL_CONS_R3:
+		leaf_expr_flavor = CIL_ROLE;
+		break;
+	case CIL_CONS_T1:
+	case CIL_CONS_T2:
+	case CIL_CONS_T3:
+		leaf_expr_flavor = CIL_TYPE;
+		break;
+	case CIL_CONS_L1:
+	case CIL_CONS_L2:
+	case CIL_CONS_H1:
+	case CIL_CONS_H2:
+		leaf_expr_flavor = CIL_LEVEL;
+		break;
+	default:
+		cil_log(CIL_ERR, "Invalid left operand (%s)\n", (char*)current->next->data);
+		goto exit;
+	}
+
+	rc = cil_verify_constraint_leaf_expr_syntax(l_flavor, r_flavor, op, expr_flavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_init(leaf_expr, leaf_expr_flavor);
+
+	cil_list_append(*leaf_expr, CIL_OP, (void *)op);
+
+	cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)l_flavor);
+
+	if (r_flavor == CIL_STRING) {
+		cil_list_append(*leaf_expr, CIL_STRING, current->next->next->data);
+	} else if (r_flavor == CIL_LIST) {
+		struct cil_list *sub_list;
+		cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list);
+		cil_list_append(*leaf_expr, CIL_LIST, &sub_list);
+	} else {
+		cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)r_flavor);
+	}
+
+	return SEPOL_OK;
+
+exit:
+
+	return SEPOL_ERR;
+}
+
+static int __cil_fill_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr, int *depth)
+{
+	int rc = SEPOL_ERR;
+	enum cil_flavor op;
+	struct cil_list *lexpr;
+	struct cil_list *rexpr;
+
+	if (current->data == NULL || current->cl_head != NULL) {
+		cil_log(CIL_ERR, "Expected a string at the start of the constraint expression\n");
+		goto exit;
+	}
+
+	if (*depth > CEXPR_MAXDEPTH) {
+		cil_log(CIL_ERR, "Max depth of %d exceeded for constraint expression\n", CEXPR_MAXDEPTH);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	op = __cil_get_constraint_operator_flavor(current->data);
+
+	rc = cil_verify_constraint_expr_syntax(current, op);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	switch (op) {
+	case CIL_EQ:
+	case CIL_NEQ:
+	case CIL_CONS_DOM:
+	case CIL_CONS_DOMBY:
+	case CIL_CONS_INCOMP:
+		(*depth)++;
+		rc = __cil_fill_constraint_leaf_expr(current, flavor, op, expr);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	case CIL_NOT:
+		rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_init(expr, flavor);
+		cil_list_append(*expr, CIL_OP, (void *)op);
+		cil_list_append(*expr, CIL_LIST, lexpr);
+		break;
+	default:
+		rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rc = __cil_fill_constraint_expr(current->next->next->cl_head, flavor, &rexpr, depth);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_init(expr, flavor);
+		cil_list_append(*expr, CIL_OP, (void *)op);
+		cil_list_append(*expr, CIL_LIST, lexpr);
+		cil_list_append(*expr, CIL_LIST, rexpr);
+		break;
+	}
+
+	(*depth)--;
+
+	return SEPOL_OK;
+exit:
+
+	return rc;
+}
+
+int cil_gen_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
+{
+	int rc = SEPOL_ERR;
+	int depth = 0;
+
+	if (current->cl_head == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_fill_constraint_expr(current->cl_head, flavor, expr, &depth);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+
+	cil_log(CIL_ERR, "Bad expression tree for constraint\n");
+	return rc;
+}
+
+int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_LIST,
+		CIL_SYN_LIST | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_booleanif *bif = NULL;
+	struct cil_tree_node *next = NULL;
+	struct cil_tree_node *cond = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_boolif_init(&bif);
+	bif->preserved_tunable = tunableif;
+
+	rc = cil_gen_expr(parse_current->next, CIL_BOOL, &bif->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cond = parse_current->next->next;
+
+	/* Destroying expr tree after stack is created*/
+	if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+		cond->cl_head->data != CIL_KEY_CONDFALSE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Conditional neither true nor false\n");
+		goto exit;
+	}
+
+	if (cond->next != NULL) {
+		cond = cond->next;
+		if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+			cond->cl_head->data != CIL_KEY_CONDFALSE) {
+			rc = SEPOL_ERR;
+			cil_log(CIL_ERR, "Conditional neither true nor false\n");
+			goto exit;
+		}
+	}
+
+
+	next = parse_current->next->next;
+	cil_tree_subtree_destroy(parse_current->next);
+	parse_current->next = next;
+
+	ast_node->flavor = CIL_BOOLEANIF;
+	ast_node->data = bif;
+
+	return SEPOL_OK;
+
+exit:
+	if (tunableif) {
+		cil_tree_log(parse_current, CIL_ERR, "Bad tunableif (treated as a booleanif due to preserve-tunables) declaration");
+	} else {
+		cil_tree_log(parse_current, CIL_ERR, "Bad booleanif declaration");
+	}
+	cil_destroy_boolif(bif);
+	return rc;
+}
+
+void cil_destroy_boolif(struct cil_booleanif *bif)
+{
+	if (bif == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&bif->str_expr, CIL_TRUE);
+	cil_list_destroy(&bif->datum_expr, CIL_FALSE);
+
+	free(bif);
+}
+
+int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_LIST,
+		CIL_SYN_LIST | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_tunableif *tif = NULL;
+	struct cil_tree_node *next = NULL;
+	struct cil_tree_node *cond = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_tunif_init(&tif);
+
+	rc = cil_gen_expr(parse_current->next, CIL_TUNABLE, &tif->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cond = parse_current->next->next;
+
+	if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+		cond->cl_head->data != CIL_KEY_CONDFALSE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Conditional neither true nor false\n");
+		goto exit;
+	}
+
+	if (cond->next != NULL) {
+		cond = cond->next;
+
+		if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+			cond->cl_head->data != CIL_KEY_CONDFALSE) {
+			rc = SEPOL_ERR;
+			cil_log(CIL_ERR, "Conditional neither true nor false\n");
+			goto exit;
+		}
+	}
+
+	/* Destroying expr tree after stack is created*/
+	next = parse_current->next->next;
+	cil_tree_subtree_destroy(parse_current->next);
+	parse_current->next = next;
+
+	ast_node->flavor = CIL_TUNABLEIF;
+	ast_node->data = tif;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad tunableif declaration");
+	cil_destroy_tunif(tif);
+	return rc;
+}
+
+void cil_destroy_tunif(struct cil_tunableif *tif)
+{
+	if (tif == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&tif->str_expr, CIL_TRUE);
+	cil_list_destroy(&tif->datum_expr, CIL_FALSE);
+
+	free(tif);
+}
+
+int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_N_LISTS,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_condblock *cb = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (ast_node->parent->flavor != CIL_BOOLEANIF && ast_node->parent->flavor != CIL_TUNABLEIF) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Conditional statements must be a direct child of a tunableif or booleanif statement.\n");
+		goto exit;
+	}
+
+	ast_node->flavor = CIL_CONDBLOCK;
+
+	cil_condblock_init(&cb);
+	cb->flavor = flavor;
+
+	ast_node->data = cb;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad %s condition declaration",
+		(char*)parse_current->data);
+	cil_destroy_condblock(cb);
+	return rc;
+}
+
+void cil_destroy_condblock(struct cil_condblock *cb)
+{
+	if (cb == NULL) {
+		return;
+	}
+
+	cil_symtab_array_destroy(cb->symtab);
+	free(cb);
+}
+
+int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_alias *alias = NULL;
+	enum cil_sym_index sym_index;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) {
+		cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_alias_init(&alias);
+
+	key = parse_current->next->data;
+
+	rc = cil_flavor_to_symtab_index(flavor, &sym_index);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)alias, (hashtab_key_t)key, sym_index, flavor);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", (char*)parse_current->data);
+	cil_destroy_alias(alias);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_alias(struct cil_alias *alias)
+{
+	if (alias == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&alias->datum);
+	alias->actual = NULL;
+
+	free(alias);
+}
+
+int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_aliasactual *aliasactual = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if ((flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) || parse_current->next->next->data == CIL_KEY_SELF) {
+		cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_aliasactual_init(&aliasactual);
+
+	aliasactual->alias_str = parse_current->next->data;
+
+	aliasactual->actual_str = parse_current->next->next->data;
+
+	ast_node->data = aliasactual;
+	ast_node->flavor = flavor;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad %s association", cil_node_to_string(parse_current));
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual)
+{
+	if (aliasactual == NULL) {
+		return;
+	}
+
+	free(aliasactual);
+}
+
+int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_typeattributeset *attrset = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_typeattributeset_init(&attrset);
+
+	attrset->attr_str = parse_current->next->data;
+
+	rc = cil_gen_expr(parse_current->next->next, CIL_TYPE, &attrset->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	ast_node->data = attrset;
+	ast_node->flavor = CIL_TYPEATTRIBUTESET;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad typeattributeset statement");
+	cil_destroy_typeattributeset(attrset);
+	return rc;
+}
+
+void cil_destroy_typeattributeset(struct cil_typeattributeset *attrset)
+{
+	if (attrset == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+	cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+	free(attrset);
+}
+
+int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_typepermissive *typeperm = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_typepermissive_init(&typeperm);
+
+	typeperm->type_str = parse_current->next->data;
+
+	ast_node->data = typeperm;
+	ast_node->flavor = CIL_TYPEPERMISSIVE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad typepermissive declaration");
+	cil_destroy_typepermissive(typeperm);
+	return rc;
+}
+
+void cil_destroy_typepermissive(struct cil_typepermissive *typeperm)
+{
+	if (typeperm == NULL) {
+		return;
+	}
+
+	free(typeperm);
+}
+
+int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *s1, *s2, *s3, *s4, *s5;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL ) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	s1 = parse_current->next->data;
+	s2 = parse_current->next->next->data;
+	s3 = parse_current->next->next->next->data;
+	s4 = parse_current->next->next->next->next->data;
+	s5 = NULL;
+
+	if (parse_current->next->next->next->next->next) {
+		if (s4 == CIL_KEY_STAR) {
+			s4 = parse_current->next->next->next->next->next->data;
+		} else {
+			s5 = parse_current->next->next->next->next->next->data;
+		}
+	}
+
+	if (s5) {
+		struct cil_nametypetransition *nametypetrans = NULL;
+
+		cil_nametypetransition_init(&nametypetrans);
+
+		nametypetrans->src_str = s1;
+		nametypetrans->tgt_str = s2;
+		nametypetrans->obj_str = s3;
+		nametypetrans->result_str = s5;
+		nametypetrans->name_str = s4;
+
+		ast_node->data = nametypetrans;
+		ast_node->flavor = CIL_NAMETYPETRANSITION;
+	} else {
+		struct cil_type_rule *rule = NULL;
+
+		cil_type_rule_init(&rule);
+
+		rule->rule_kind = CIL_TYPE_TRANSITION;
+		rule->src_str = s1;
+		rule->tgt_str = s2;
+		rule->obj_str = s3;
+		rule->result_str = s4;
+
+		ast_node->data = rule;
+		ast_node->flavor = CIL_TYPE_RULE;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad typetransition declaration");
+	return rc;
+}
+
+void cil_destroy_name(struct cil_name *name)
+{
+	if (name == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&name->datum);
+	free(name);
+}
+
+void cil_destroy_typetransition(struct cil_nametypetransition *nametypetrans)
+{
+	if (nametypetrans == NULL) {
+		return;
+	}
+
+	free(nametypetrans);
+}
+
+int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_rangetransition *rangetrans = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL ) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_rangetransition_init(&rangetrans);
+
+	rangetrans->src_str = parse_current->next->data;
+	rangetrans->exec_str = parse_current->next->next->data;
+	rangetrans->obj_str = parse_current->next->next->next->data;
+
+	rangetrans->range_str = NULL;
+
+	if (parse_current->next->next->next->next->cl_head == NULL) {
+		rangetrans->range_str = parse_current->next->next->next->next->data;
+	} else {
+		cil_levelrange_init(&rangetrans->range);
+
+		rc = cil_fill_levelrange(parse_current->next->next->next->next->cl_head, rangetrans->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = rangetrans;
+	ast_node->flavor = CIL_RANGETRANSITION;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad rangetransition declaration");
+	cil_destroy_rangetransition(rangetrans);
+	return rc;
+}
+
+void cil_destroy_rangetransition(struct cil_rangetransition *rangetrans)
+{
+	if (rangetrans == NULL) {
+		return;
+	}
+
+	if (rangetrans->range_str == NULL && rangetrans->range != NULL) {
+		cil_destroy_levelrange(rangetrans->range);
+	}
+
+	free(rangetrans);
+}
+
+int cil_gen_sensitivity(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_sens *sens = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_sens_init(&sens);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sens, (hashtab_key_t)key, CIL_SYM_SENS, CIL_SENS);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sensitivity declaration");
+	cil_destroy_sensitivity(sens);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_sensitivity(struct cil_sens *sens)
+{
+	if (sens == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&sens->datum);
+
+	cil_list_destroy(&sens->cats_list, CIL_FALSE);
+
+	free(sens);
+}
+
+int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_cat *cat = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_cat_init(&cat);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)cat, (hashtab_key_t)key, CIL_SYM_CATS, CIL_CAT);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad category declaration");
+	cil_destroy_category(cat);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_category(struct cil_cat *cat)
+{
+	if (cat == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&cat->datum);
+	free(cat);
+}
+
+int cil_gen_catset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_catset *catset = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_catset_init(&catset);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)catset, (hashtab_key_t)key, CIL_SYM_CATS, CIL_CATSET);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fill_cats(parse_current->next->next, &catset->cats);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad categoryset declaration");
+	cil_destroy_catset(catset);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_catset(struct cil_catset *catset)
+{
+	if (catset == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&catset->datum);
+
+	cil_destroy_cats(catset->cats);
+
+	free(catset);
+}
+
+int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_catorder *catorder = NULL;
+	struct cil_list_item *curr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc !=  SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_catorder_init(&catorder);
+
+	rc = cil_fill_list(parse_current->next->cl_head, CIL_CATORDER, &catorder->cat_list_str);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_for_each(curr, catorder->cat_list_str) {
+		if (curr->data == CIL_KEY_UNORDERED) {
+			cil_log(CIL_ERR, "Category order cannot be unordered.\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	ast_node->data = catorder;
+	ast_node->flavor = CIL_CATORDER;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad categoryorder declaration");
+	cil_destroy_catorder(catorder);
+	return rc;
+}
+
+void cil_destroy_catorder(struct cil_catorder *catorder)
+{
+	if (catorder == NULL) {
+		return;
+	}
+
+	if (catorder->cat_list_str != NULL) {
+		cil_list_destroy(&catorder->cat_list_str, 1);
+	}
+
+	free(catorder);
+}
+
+int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_sensorder *sensorder = NULL;
+	struct cil_list_item *curr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_sensorder_init(&sensorder);
+
+	rc = cil_fill_list(parse_current->next->cl_head, CIL_SENSITIVITYORDER, &sensorder->sens_list_str);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_list_for_each(curr, sensorder->sens_list_str) {
+		if (curr->data == CIL_KEY_UNORDERED) {
+			cil_log(CIL_ERR, "Sensitivy order cannot be unordered.\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	ast_node->data = sensorder;
+	ast_node->flavor = CIL_SENSITIVITYORDER;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sensitivityorder declaration");
+	cil_destroy_sensitivityorder(sensorder);
+	return rc;
+}
+
+void cil_destroy_sensitivityorder(struct cil_sensorder *sensorder)
+{
+	if (sensorder == NULL) {
+		return;
+	}
+
+	if (sensorder->sens_list_str != NULL) {
+		cil_list_destroy(&sensorder->sens_list_str, CIL_TRUE);
+	}
+
+	free(sensorder);
+}
+
+int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_senscat *senscat = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_senscat_init(&senscat);
+
+	senscat->sens_str = parse_current->next->data;
+
+	rc = cil_fill_cats(parse_current->next->next, &senscat->cats);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = senscat;
+	ast_node->flavor = CIL_SENSCAT;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad sensitivitycategory declaration");
+	cil_destroy_senscat(senscat);
+	return rc;
+}
+
+void cil_destroy_senscat(struct cil_senscat *senscat)
+{
+	if (senscat == NULL) {
+		return;
+	}
+
+	cil_destroy_cats(senscat->cats);
+
+	free(senscat);
+}
+
+int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_level *level = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_level_init(&level);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)level, (hashtab_key_t)key, CIL_SYM_LEVELS, CIL_LEVEL);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fill_level(parse_current->next->next->cl_head, level);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad level declaration");
+	cil_destroy_level(level);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_level(struct cil_level *level)
+{
+	if (level == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&level->datum);
+
+	cil_destroy_cats(level->cats);
+
+	free(level);
+}
+
+/* low should be pointing to either the name of the low level or to an open paren for an anonymous low level */
+int cil_fill_levelrange(struct cil_tree_node *low, struct cil_levelrange *lvlrange)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+
+	if (low == NULL || lvlrange == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(low, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+
+		goto exit;
+	}
+
+	if (low->cl_head == NULL) {
+		lvlrange->low_str = low->data;
+	} else {
+		cil_level_init(&lvlrange->low);
+		rc = cil_fill_level(low->cl_head, lvlrange->low);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (low->next->cl_head == NULL) {
+		lvlrange->high_str = low->next->data;
+	} else {
+		cil_level_init(&lvlrange->high);
+		rc = cil_fill_level(low->next->cl_head, lvlrange->high);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad levelrange\n");
+	return rc;
+}
+
+int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_levelrange *lvlrange = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_levelrange_init(&lvlrange);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)lvlrange, (hashtab_key_t)key, CIL_SYM_LEVELRANGES, CIL_LEVELRANGE);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fill_levelrange(parse_current->next->next->cl_head, lvlrange);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad levelrange declaration");
+	cil_destroy_levelrange(lvlrange);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_levelrange(struct cil_levelrange *lvlrange)
+{
+	if (lvlrange == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&lvlrange->datum);
+
+	if (lvlrange->low_str == NULL) {
+		cil_destroy_level(lvlrange->low);
+	}
+
+	if (lvlrange->high_str == NULL) {
+		cil_destroy_level(lvlrange->high);
+	}
+
+	free(lvlrange);
+}
+
+int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_constrain *cons = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_constrain_init(&cons);
+
+	rc = cil_fill_classperms_list(parse_current->next, &cons->classperms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_constraint_expr(parse_current->next->next, flavor, &cons->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = cons;
+	ast_node->flavor = flavor;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad constrain declaration");
+	cil_destroy_constrain(cons);
+	return rc;
+}
+
+void cil_destroy_constrain(struct cil_constrain *cons)
+{
+	if (cons == NULL) {
+		return;
+	}
+
+	cil_destroy_classperms_list(&cons->classperms);
+	cil_list_destroy(&cons->str_expr, CIL_TRUE);
+	cil_list_destroy(&cons->datum_expr, CIL_FALSE);
+
+	free(cons);
+}
+
+int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_validatetrans *validtrans = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_validatetrans_init(&validtrans);
+
+	validtrans->class_str = parse_current->next->data;
+
+	rc = cil_gen_constraint_expr(parse_current->next->next, flavor, &validtrans->str_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	ast_node->data = validtrans;
+	ast_node->flavor = flavor;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad validatetrans declaration");
+	cil_destroy_validatetrans(validtrans);
+	return rc;
+
+
+}
+
+void cil_destroy_validatetrans(struct cil_validatetrans *validtrans)
+{
+	if (validtrans == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&validtrans->str_expr, CIL_TRUE);
+	cil_list_destroy(&validtrans->datum_expr, CIL_FALSE);
+
+	free(validtrans);
+}
+
+/* Fills in context starting from user */
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+
+	if (user_node == NULL || context == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(user_node, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	context->user_str = user_node->data;
+	context->role_str = user_node->next->data;
+	context->type_str = user_node->next->next->data;
+
+	context->range_str = NULL;
+
+	if (user_node->next->next->next->cl_head == NULL) {
+		context->range_str = user_node->next->next->next->data;
+	} else {
+		cil_levelrange_init(&context->range);
+
+		rc = cil_fill_levelrange(user_node->next->next->next->cl_head, context->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad context\n");
+	return rc;
+}
+
+int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_context *context = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_context_init(&context);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)context, (hashtab_key_t)key, CIL_SYM_CONTEXTS, CIL_CONTEXT);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_fill_context(parse_current->next->next->cl_head, context);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad context declaration");
+	cil_destroy_context(context);
+	cil_clear_node(ast_node);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_context(struct cil_context *context)
+{
+	if (context == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&context->datum);;
+
+	if (context->range_str == NULL && context->range != NULL) {
+		cil_destroy_levelrange(context->range);
+	}
+
+	free(context);
+}
+
+int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_filecon *filecon = NULL;
+	char *type = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	type = parse_current->next->next->data;
+	cil_filecon_init(&filecon);
+
+	filecon->path_str = parse_current->next->data;
+
+	if (type == CIL_KEY_FILE) {
+		filecon->type = CIL_FILECON_FILE;
+	} else if (type == CIL_KEY_DIR) {
+		filecon->type = CIL_FILECON_DIR;
+	} else if (type == CIL_KEY_CHAR) {
+		filecon->type = CIL_FILECON_CHAR;
+	} else if (type == CIL_KEY_BLOCK) {
+		filecon->type = CIL_FILECON_BLOCK;
+	} else if (type == CIL_KEY_SOCKET) {
+		filecon->type = CIL_FILECON_SOCKET;
+	} else if (type == CIL_KEY_PIPE) {
+		filecon->type = CIL_FILECON_PIPE;
+	} else if (type == CIL_KEY_SYMLINK) {
+		filecon->type = CIL_FILECON_SYMLINK;
+	} else if (type == CIL_KEY_ANY) {
+		filecon->type = CIL_FILECON_ANY;
+	} else {
+		cil_log(CIL_ERR, "Invalid file type\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (parse_current->next->next->next->cl_head == NULL) {
+		filecon->context_str = parse_current->next->next->next->data;
+	} else {
+		if (parse_current->next->next->next->cl_head->next == NULL) {
+			filecon->context = NULL;
+		} else {
+			cil_context_init(&filecon->context);
+
+			rc = cil_fill_context(parse_current->next->next->next->cl_head, filecon->context);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	ast_node->data = filecon;
+	ast_node->flavor = CIL_FILECON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad filecon declaration");
+	cil_destroy_filecon(filecon);
+	return rc;
+}
+
+//TODO: Should we be checking if the pointer is NULL when passed in?
+void cil_destroy_filecon(struct cil_filecon *filecon)
+{
+	if (filecon == NULL) {
+		return;
+	}
+
+	if (filecon->context_str == NULL && filecon->context != NULL) {
+		cil_destroy_context(filecon->context);
+	}
+
+	free(filecon);
+}
+
+int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_portcon *portcon = NULL;
+	char *proto;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_portcon_init(&portcon);
+
+	proto = parse_current->next->data;
+	if (proto == CIL_KEY_UDP) {
+		portcon->proto = CIL_PROTOCOL_UDP;
+	} else if (proto == CIL_KEY_TCP) {
+		portcon->proto = CIL_PROTOCOL_TCP;
+	} else if (proto == CIL_KEY_DCCP) {
+		portcon->proto = CIL_PROTOCOL_DCCP;
+	} else {
+		cil_log(CIL_ERR, "Invalid protocol\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (parse_current->next->next->cl_head != NULL) {
+		if (parse_current->next->next->cl_head->next != NULL
+		&& parse_current->next->next->cl_head->next->next == NULL) {
+			rc = cil_fill_integer(parse_current->next->next->cl_head, &portcon->port_low);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper port specified\n");
+				goto exit;
+			}
+			rc = cil_fill_integer(parse_current->next->next->cl_head->next, &portcon->port_high);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper port specified\n");
+				goto exit;
+			}
+		} else {
+			cil_log(CIL_ERR, "Improper port range specified\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		rc = cil_fill_integer(parse_current->next->next, &portcon->port_low);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Improper port specified\n");
+			goto exit;
+		}
+		portcon->port_high = portcon->port_low;
+	}
+
+	if (parse_current->next->next->next->cl_head == NULL ) {
+		portcon->context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&portcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, portcon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = portcon;
+	ast_node->flavor = CIL_PORTCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad portcon declaration");
+	cil_destroy_portcon(portcon);
+	return rc;
+}
+
+void cil_destroy_portcon(struct cil_portcon *portcon)
+{
+	if (portcon == NULL) {
+		return;
+	}
+
+	if (portcon->context_str == NULL && portcon->context != NULL) {
+		cil_destroy_context(portcon->context);
+	}
+
+	free(portcon);
+}
+
+int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_nodecon *nodecon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_nodecon_init(&nodecon);
+
+	if (parse_current->next->cl_head == NULL ) {
+		nodecon->addr_str = parse_current->next->data;
+	} else {
+		cil_ipaddr_init(&nodecon->addr);
+
+		rc = cil_fill_ipaddr(parse_current->next->cl_head, nodecon->addr);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (parse_current->next->next->cl_head == NULL ) {
+		nodecon->mask_str = parse_current->next->next->data;
+	} else {
+		cil_ipaddr_init(&nodecon->mask);
+
+		rc = cil_fill_ipaddr(parse_current->next->next->cl_head, nodecon->mask);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (parse_current->next->next->next->cl_head == NULL ) {
+		nodecon->context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&nodecon->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, nodecon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = nodecon;
+	ast_node->flavor = CIL_NODECON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad nodecon declaration");
+	cil_destroy_nodecon(nodecon);
+	return rc;
+}
+
+void cil_destroy_nodecon(struct cil_nodecon *nodecon)
+{
+	if (nodecon == NULL) {
+		return;
+	}
+
+	if (nodecon->addr_str == NULL && nodecon->addr != NULL) {
+		cil_destroy_ipaddr(nodecon->addr);
+	}
+
+	if (nodecon->mask_str == NULL && nodecon->mask != NULL) {
+		cil_destroy_ipaddr(nodecon->mask);
+	}
+
+	if (nodecon->context_str == NULL && nodecon->context != NULL) {
+		cil_destroy_context(nodecon->context);
+	}
+
+	free(nodecon);
+}
+
+int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_genfscon *genfscon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_genfscon_init(&genfscon);
+
+	genfscon->fs_str = parse_current->next->data;
+	genfscon->path_str = parse_current->next->next->data;
+
+	if (parse_current->next->next->next->cl_head == NULL ) {
+		genfscon->context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&genfscon->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, genfscon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = genfscon;
+	ast_node->flavor = CIL_GENFSCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad genfscon declaration");
+	cil_destroy_genfscon(genfscon);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_genfscon(struct cil_genfscon *genfscon)
+{
+	if (genfscon == NULL) {
+		return;
+	}
+
+	if (genfscon->context_str == NULL && genfscon->context != NULL) {
+		cil_destroy_context(genfscon->context);
+	}
+
+	free(genfscon);
+}
+
+
+int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_netifcon *netifcon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_netifcon_init(&netifcon);
+
+	netifcon->interface_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		netifcon->if_context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&netifcon->if_context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, netifcon->if_context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (parse_current->next->next->next->cl_head == NULL) {
+		netifcon->packet_context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&netifcon->packet_context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, netifcon->packet_context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = netifcon;
+	ast_node->flavor = CIL_NETIFCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad netifcon declaration");
+	cil_destroy_netifcon(netifcon);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_netifcon(struct cil_netifcon *netifcon)
+{
+	if (netifcon == NULL) {
+		return;
+	}
+
+	if (netifcon->if_context_str == NULL && netifcon->if_context != NULL) {
+		cil_destroy_context(netifcon->if_context);
+	}
+
+	if (netifcon->packet_context_str == NULL && netifcon->packet_context != NULL) {
+		cil_destroy_context(netifcon->packet_context);
+	}
+
+	free(netifcon);
+}
+
+int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_pirqcon *pirqcon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_pirqcon_init(&pirqcon);
+
+	rc = cil_fill_integer(parse_current->next, &pirqcon->pirq);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->next->cl_head == NULL) {
+		pirqcon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&pirqcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, pirqcon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = pirqcon;
+	ast_node->flavor = CIL_PIRQCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad pirqcon declaration");
+	cil_destroy_pirqcon(pirqcon);
+	return rc;
+}
+
+void cil_destroy_pirqcon(struct cil_pirqcon *pirqcon)
+{
+	if (pirqcon == NULL) {
+		return;
+	}
+
+	if (pirqcon->context_str == NULL && pirqcon->context != NULL) {
+		cil_destroy_context(pirqcon->context);
+	}
+
+	free(pirqcon);
+}
+
+int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_iomemcon *iomemcon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_iomemcon_init(&iomemcon);
+
+	if (parse_current->next->cl_head != NULL) {
+		if (parse_current->next->cl_head->next != NULL &&
+		    parse_current->next->cl_head->next->next == NULL) {
+			rc = cil_fill_integer64(parse_current->next->cl_head, &iomemcon->iomem_low);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper iomem specified\n");
+				goto exit;
+			}
+			rc = cil_fill_integer64(parse_current->next->cl_head->next, &iomemcon->iomem_high);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper iomem specified\n");
+				goto exit;
+			}
+		} else {
+			cil_log(CIL_ERR, "Improper iomem range specified\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		rc = cil_fill_integer64(parse_current->next, &iomemcon->iomem_low);;
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Improper iomem specified\n");
+			goto exit;
+		}
+		iomemcon->iomem_high = iomemcon->iomem_low;
+	}
+
+	if (parse_current->next->next->cl_head == NULL ) {
+		iomemcon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&iomemcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, iomemcon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = iomemcon;
+	ast_node->flavor = CIL_IOMEMCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad iomemcon declaration");
+	cil_destroy_iomemcon(iomemcon);
+	return rc;
+}
+
+void cil_destroy_iomemcon(struct cil_iomemcon *iomemcon)
+{
+	if (iomemcon == NULL) {
+		return;
+	}
+
+	if (iomemcon->context_str == NULL && iomemcon->context != NULL) {
+		cil_destroy_context(iomemcon->context);
+	}
+
+	free(iomemcon);
+}
+
+int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_ioportcon *ioportcon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_ioportcon_init(&ioportcon);
+
+	if (parse_current->next->cl_head != NULL) {
+		if (parse_current->next->cl_head->next != NULL &&
+		    parse_current->next->cl_head->next->next == NULL) {
+			rc = cil_fill_integer(parse_current->next->cl_head, &ioportcon->ioport_low);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper ioport specified\n");
+				goto exit;
+			}
+			rc = cil_fill_integer(parse_current->next->cl_head->next, &ioportcon->ioport_high);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper ioport specified\n");
+				goto exit;
+			}
+		} else {
+			cil_log(CIL_ERR, "Improper ioport range specified\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		rc = cil_fill_integer(parse_current->next, &ioportcon->ioport_low);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Improper ioport specified\n");
+			goto exit;
+		}
+		ioportcon->ioport_high = ioportcon->ioport_low;
+	}
+
+	if (parse_current->next->next->cl_head == NULL ) {
+		ioportcon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&ioportcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, ioportcon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = ioportcon;
+	ast_node->flavor = CIL_IOPORTCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad ioportcon declaration");
+	cil_destroy_ioportcon(ioportcon);
+	return rc;
+}
+
+void cil_destroy_ioportcon(struct cil_ioportcon *ioportcon)
+{
+	if (ioportcon == NULL) {
+		return;
+	}
+
+	if (ioportcon->context_str == NULL && ioportcon->context != NULL) {
+		cil_destroy_context(ioportcon->context);
+	}
+
+	free(ioportcon);
+}
+
+int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_pcidevicecon *pcidevicecon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_pcidevicecon_init(&pcidevicecon);
+
+	rc = cil_fill_integer(parse_current->next, &pcidevicecon->dev);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (parse_current->next->next->cl_head == NULL) {
+		pcidevicecon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&pcidevicecon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, pcidevicecon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = pcidevicecon;
+	ast_node->flavor = CIL_PCIDEVICECON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad pcidevicecon declaration");
+	cil_destroy_pcidevicecon(pcidevicecon);
+	return rc;
+}
+
+void cil_destroy_pcidevicecon(struct cil_pcidevicecon *pcidevicecon)
+{
+	if (pcidevicecon == NULL) {
+		return;
+	}
+
+	if (pcidevicecon->context_str == NULL && pcidevicecon->context != NULL) {
+		cil_destroy_context(pcidevicecon->context);
+	}
+
+	free(pcidevicecon);
+}
+
+int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_devicetreecon *devicetreecon = NULL;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_devicetreecon_init(&devicetreecon);
+
+	devicetreecon->path = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head == NULL) {
+		devicetreecon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&devicetreecon->context);
+
+		rc = cil_fill_context(parse_current->next->next->cl_head, devicetreecon->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = devicetreecon;
+	ast_node->flavor = CIL_DEVICETREECON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad devicetreecon declaration");
+	cil_destroy_devicetreecon(devicetreecon);
+	return rc;
+}
+
+void cil_destroy_devicetreecon(struct cil_devicetreecon *devicetreecon)
+{
+	if (devicetreecon == NULL) {
+		return;
+	}
+
+	if (devicetreecon->context_str == NULL && devicetreecon->context != NULL) {
+		cil_destroy_context(devicetreecon->context);
+	}
+
+	free(devicetreecon);
+}
+
+int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *type = NULL;
+	struct cil_fsuse *fsuse = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	type = parse_current->next->data;
+
+	cil_fsuse_init(&fsuse);
+
+	if (type == CIL_KEY_XATTR) {
+		fsuse->type = CIL_FSUSE_XATTR;
+	} else if (type == CIL_KEY_TASK) {
+		fsuse->type = CIL_FSUSE_TASK;
+	} else if (type == CIL_KEY_TRANS) {
+		fsuse->type = CIL_FSUSE_TRANS;
+	} else {
+		cil_log(CIL_ERR, "Invalid fsuse type\n");
+		goto exit;
+	}
+
+	fsuse->fs_str = parse_current->next->next->data;
+
+	if (parse_current->next->next->next->cl_head == NULL) {
+		fsuse->context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&fsuse->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, fsuse->context);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	ast_node->data = fsuse;
+	ast_node->flavor = CIL_FSUSE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad fsuse declaration");
+	cil_destroy_fsuse(fsuse);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_fsuse(struct cil_fsuse *fsuse)
+{
+	if (fsuse == NULL) {
+		return;
+	}
+
+	if (fsuse->context_str == NULL && fsuse->context != NULL) {
+		cil_destroy_context(fsuse->context);
+	}
+
+	free(fsuse);
+}
+
+void cil_destroy_param(struct cil_param *param)
+{
+	if (param == NULL) {
+		return;
+	}
+
+	free(param);
+}
+
+int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	char *key = NULL;
+	struct cil_macro *macro = NULL;
+	struct cil_tree_node *macro_content = NULL;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+		CIL_SYN_N_LISTS | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/ sizeof(*syntax);
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc =__cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_macro_init(&macro);
+
+	key = parse_current->next->data;
+
+	struct cil_tree_node *current_item = parse_current->next->next->cl_head;
+	while (current_item != NULL) {
+		enum cil_syntax param_syntax[] = {
+			CIL_SYN_STRING,
+			CIL_SYN_STRING,
+			CIL_SYN_END
+		};
+		int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax);
+		char *kind = NULL;
+		struct cil_param *param = NULL;
+
+		rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		if (macro->params == NULL) {
+			cil_list_init(&macro->params, CIL_LIST_ITEM);
+		}
+
+		kind = current_item->cl_head->data;
+		cil_param_init(&param);
+
+		if (kind == CIL_KEY_TYPE) {
+			param->flavor = CIL_TYPE;
+		} else if (kind == CIL_KEY_ROLE) {
+			param->flavor = CIL_ROLE;
+		} else if (kind == CIL_KEY_USER) {
+			param->flavor = CIL_USER;
+		} else if (kind == CIL_KEY_SENSITIVITY) {
+			param->flavor = CIL_SENS;
+		} else if (kind == CIL_KEY_CATEGORY) {
+			param->flavor = CIL_CAT;
+		} else if (kind == CIL_KEY_CATSET) {
+			param->flavor = CIL_CATSET;
+		} else if (kind == CIL_KEY_LEVEL) {
+			param->flavor = CIL_LEVEL;
+		} else if (kind == CIL_KEY_LEVELRANGE) {
+			param->flavor = CIL_LEVELRANGE;
+		} else if (kind == CIL_KEY_CLASS) {
+			param->flavor = CIL_CLASS;
+		} else if (kind == CIL_KEY_IPADDR) {
+			param->flavor = CIL_IPADDR;
+		} else if (kind == CIL_KEY_MAP_CLASS) {
+			param->flavor = CIL_MAP_CLASS;
+		} else if (kind == CIL_KEY_CLASSPERMISSION) {
+			param->flavor = CIL_CLASSPERMISSION;
+		} else if (kind == CIL_KEY_BOOL) {
+			param->flavor = CIL_BOOL;
+		} else if (kind == CIL_KEY_STRING) {
+			param->flavor = CIL_NAME;
+		} else if (kind == CIL_KEY_NAME) {
+			param->flavor = CIL_NAME;
+		} else {
+			cil_log(CIL_ERR, "The kind %s is not allowed as a parameter\n",kind);
+			cil_destroy_param(param);
+			goto exit;
+		}
+
+		param->str =  current_item->cl_head->next->data;
+
+		rc = __cil_verify_name(param->str);
+		if (rc != SEPOL_OK) {
+			cil_destroy_param(param);
+			goto exit;
+		}
+
+		//walk current list and check for duplicate parameters
+		struct cil_list_item *curr_param;
+		cil_list_for_each(curr_param, macro->params) {
+			if (param->str == ((struct cil_param*)curr_param->data)->str) {
+				if (param->flavor == ((struct cil_param*)curr_param->data)->flavor) {
+					cil_log(CIL_ERR, "Duplicate parameter\n");
+					cil_destroy_param(param);
+					goto exit;
+				}
+			}
+		}
+
+		cil_list_append(macro->params, CIL_PARAM, param);
+
+		current_item = current_item->next;
+	}
+
+	/* we don't want the tree walker to walk the macro parameters (they were just handled above), so the subtree is deleted, and the next pointer of the
+           node containing the macro name is updated to point to the start of the macro content */
+	macro_content = parse_current->next->next->next;
+	cil_tree_subtree_destroy(parse_current->next->next);
+	parse_current->next->next = macro_content;
+	if (macro_content == NULL) {
+		/* No statements in macro and macro parameter list was last node */
+		parse_current->parent->cl_tail = parse_current->next;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)macro, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_MACRO);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad macro declaration");
+	cil_destroy_macro(macro);
+	cil_clear_node(ast_node);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_macro(struct cil_macro *macro)
+{
+	if (macro == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&macro->datum);
+	cil_symtab_array_destroy(macro->symtab);
+
+	if (macro->params != NULL) {
+		cil_list_destroy(&macro->params, 1);
+	}
+
+	free(macro);
+}
+
+int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_LIST | CIL_SYN_EMPTY_LIST | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_call *call = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_call_init(&call);
+
+	call->macro_str = parse_current->next->data;
+
+	if (parse_current->next->next != NULL) {
+		cil_tree_init(&call->args_tree);
+		cil_copy_ast(db, parse_current->next->next, call->args_tree->root);
+	}
+
+	ast_node->data = call;
+	ast_node->flavor = CIL_CALL;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad macro call");
+	cil_destroy_call(call);
+	return rc;
+}
+
+void cil_destroy_call(struct cil_call *call)
+{
+	if (call == NULL) {
+		return;
+	}
+
+	call->macro = NULL;
+
+	if (call->args_tree != NULL) {
+		cil_tree_destroy(&call->args_tree);
+	}
+
+	if (call->args != NULL) {
+		cil_list_destroy(&call->args, 1);
+	}
+
+	free(call);
+}
+
+void cil_destroy_args(struct cil_args *args)
+{
+	if (args == NULL) {
+		return;
+	}
+
+	if (args->arg_str != NULL) {
+		args->arg_str = NULL;
+	} else if (args->arg != NULL) {
+		struct cil_tree_node *node = args->arg->nodes->head->data;
+		switch (args->flavor) {
+		case CIL_NAME:
+			break;
+		case CIL_CATSET:
+			cil_destroy_catset((struct cil_catset *)args->arg);
+			free(node);
+			break;
+		case CIL_LEVEL:
+			cil_destroy_level((struct cil_level *)args->arg);
+			free(node);
+			break;
+		case CIL_LEVELRANGE:
+			cil_destroy_levelrange((struct cil_levelrange *)args->arg);
+			free(node);
+			break;
+		case CIL_IPADDR:
+			cil_destroy_ipaddr((struct cil_ipaddr *)args->arg);
+			free(node);
+			break;
+		case CIL_CLASSPERMISSION:
+			cil_destroy_classpermission((struct cil_classpermission *)args->arg);
+			free(node);
+			break;
+		default:
+			cil_log(CIL_ERR, "Destroying arg with the unexpected flavor=%d\n",args->flavor);
+			break;
+		}
+	}
+
+	args->param_str = NULL;
+	args->arg = NULL;
+
+	free(args);
+}
+
+int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_N_LISTS | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_optional *optional = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_optional_init(&optional);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)optional, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_OPTIONAL);
+	if (rc != SEPOL_OK)
+		goto exit;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad optional");
+	cil_destroy_optional(optional);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_optional(struct cil_optional *optional)
+{
+	if (optional == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&optional->datum);
+	free(optional);
+}
+
+int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_policycap *polcap = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_policycap_init(&polcap);
+
+	key = parse_current->next->data;
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)polcap, (hashtab_key_t)key, CIL_SYM_POLICYCAPS, CIL_POLICYCAP);
+	if (rc != SEPOL_OK)
+		goto exit;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad policycap statement");
+	cil_destroy_policycap(polcap);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_policycap(struct cil_policycap *polcap)
+{
+	if (polcap == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&polcap->datum);
+	free(polcap);
+}
+
+int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	char *key = NULL;
+	struct cil_ipaddr *ipaddr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_ipaddr_init(&ipaddr);
+
+	key  = parse_current->next->data;
+
+	rc = cil_fill_ipaddr(parse_current->next->next, ipaddr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)ipaddr, (hashtab_key_t)key, CIL_SYM_IPADDRS, CIL_IPADDR);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad ipaddr statement");
+	cil_destroy_ipaddr(ipaddr);
+	cil_clear_node(ast_node);
+	return rc;
+}
+
+void cil_destroy_ipaddr(struct cil_ipaddr *ipaddr)
+{
+	if (ipaddr == NULL) {
+		return;
+	}
+
+	cil_symtab_datum_destroy(&ipaddr->datum);
+	free(ipaddr);
+}
+
+int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer)
+{
+	int rc = SEPOL_ERR;
+	char *endptr = NULL;
+	int val;
+
+	if (int_node == NULL || integer == NULL) {
+		goto exit;
+	}
+
+	errno = 0;
+	val = strtol(int_node->data, &endptr, 10);
+	if (errno != 0 || endptr == int_node->data || *endptr != '\0') {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	*integer = val;
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to create integer from string\n");
+	return rc;
+}
+
+int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer)
+{
+	int rc = SEPOL_ERR;
+	char *endptr = NULL;
+	uint64_t val;
+
+	if (int_node == NULL || integer == NULL) {
+		goto exit;
+	}
+
+	errno = 0;
+	val = strtoull(int_node->data, &endptr, 10);
+	if (errno != 0 || endptr == int_node->data || *endptr != '\0') {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	*integer = val;
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Failed to create integer from string\n");
+	return rc;
+}
+
+int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr)
+{
+	int rc = SEPOL_ERR;
+
+	if (addr_node == NULL || addr == NULL) {
+		goto exit;
+	}
+
+	if (addr_node->cl_head != NULL ||  addr_node->next != NULL) {
+		goto exit;
+	}
+
+	if (strchr(addr_node->data, '.') != NULL) {
+		addr->family = AF_INET;
+	} else {
+		addr->family = AF_INET6;
+	}
+
+	rc = inet_pton(addr->family, addr_node->data, &addr->ip);
+	if (rc != 1) {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad ip address or netmask\n"); 
+	return rc;
+}
+
+int cil_fill_level(struct cil_tree_node *curr, struct cil_level *level)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	if (curr == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(curr, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	level->sens_str = curr->data;
+	if (curr->next != NULL) {
+		rc = cil_fill_cats(curr->next, &level->cats);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Bad level\n");
+	return rc;
+}
+
+int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats)
+{
+	int rc = SEPOL_ERR;
+
+	cil_cats_init(cats);
+
+	rc = cil_gen_expr(curr, CIL_CAT, &(*cats)->str_expr);
+	if (rc != SEPOL_OK) {
+		cil_destroy_cats(*cats);
+	}
+
+	return rc;
+}
+
+void cil_destroy_cats(struct cil_cats *cats)
+{
+	if (cats == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&cats->str_expr, CIL_TRUE);
+
+	cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+
+	free(cats);
+}
+int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_bounds *bounds = NULL;
+	int rc = SEPOL_ERR;
+
+	if (db == NULL || parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_bounds_init(&bounds);
+
+	bounds->parent_str = parse_current->next->data;
+	bounds->child_str = parse_current->next->next->data;
+
+	ast_node->data = bounds;
+
+	switch (flavor) {
+	case CIL_USER:
+		ast_node->flavor = CIL_USERBOUNDS;
+		break;
+	case CIL_ROLE:
+		ast_node->flavor = CIL_ROLEBOUNDS;
+		break;
+	case CIL_TYPE:
+		ast_node->flavor = CIL_TYPEBOUNDS;
+		break;
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad bounds declaration");
+	cil_destroy_bounds(bounds);
+	return rc;
+}
+
+void cil_destroy_bounds(struct cil_bounds *bounds)
+{
+	if (bounds == NULL) {
+		return;
+	}
+
+	free(bounds);
+}
+
+int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+	int rc = SEPOL_ERR;
+	struct cil_default *def = NULL;
+	char *object;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_default_init(&def);
+
+	def->flavor = flavor;
+
+	if (parse_current->next->cl_head == NULL) {
+		cil_list_init(&def->class_strs, CIL_CLASS);
+		cil_list_append(def->class_strs, CIL_STRING, parse_current->next->data);
+		rc = SEPOL_OK;
+	} else {
+		rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASS, &def->class_strs);
+	}
+
+	object = parse_current->next->next->data;
+	if (object == CIL_KEY_SOURCE) {
+		def->object = CIL_DEFAULT_SOURCE;
+	} else if (object == CIL_KEY_TARGET) {
+		def->object = CIL_DEFAULT_TARGET;
+	} else {
+		cil_log(CIL_ERR,"Expected either 'source' or 'target'\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	ast_node->data = def;
+	ast_node->flavor = flavor;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", cil_node_to_string(parse_current));
+	cil_destroy_default(def);
+	return rc;
+}
+
+void cil_destroy_default(struct cil_default *def)
+{
+	if (def == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&def->class_strs, CIL_TRUE);
+
+	cil_list_destroy(&def->class_datums, CIL_FALSE);
+
+	free(def);
+}
+
+int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_defaultrange *def = NULL;
+	char *object;
+	char *range;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_defaultrange_init(&def);
+
+	if (parse_current->next->cl_head == NULL) {
+		cil_list_init(&def->class_strs, CIL_CLASS);
+		cil_list_append(def->class_strs, CIL_STRING, parse_current->next->data);
+		rc = SEPOL_OK;
+	} else {
+		rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASS, &def->class_strs);
+	}
+
+	object = parse_current->next->next->data;
+	range = parse_current->next->next->next->data;
+	if (object == CIL_KEY_SOURCE) {
+		if (range == CIL_KEY_LOW) {
+			def->object_range = CIL_DEFAULT_SOURCE_LOW;
+		} else if (range == CIL_KEY_HIGH) {
+			def->object_range = CIL_DEFAULT_SOURCE_HIGH;
+		} else if (range == CIL_KEY_LOW_HIGH) {
+			def->object_range = CIL_DEFAULT_SOURCE_LOW_HIGH;
+		} else {
+			cil_log(CIL_ERR,"Expected 'low', 'high', or 'low-high'\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else if (parse_current->next->next->data == CIL_KEY_TARGET) {
+		if (range == CIL_KEY_LOW) {
+			def->object_range = CIL_DEFAULT_TARGET_LOW;
+		} else if (range == CIL_KEY_HIGH) {
+			def->object_range = CIL_DEFAULT_TARGET_HIGH;
+		} else if (range == CIL_KEY_LOW_HIGH) {
+			def->object_range = CIL_DEFAULT_TARGET_LOW_HIGH;
+		} else {
+			cil_log(CIL_ERR,"Expected 'low', 'high', or 'low-high'\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		cil_log(CIL_ERR,"Expected either \'source\' or \'target\'\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	ast_node->data = def;
+	ast_node->flavor = CIL_DEFAULTRANGE;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad defaultrange declaration");
+	cil_destroy_defaultrange(def);
+	return rc;
+}
+
+void cil_destroy_defaultrange(struct cil_defaultrange *def)
+{
+	if (def == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&def->class_strs, CIL_TRUE);
+
+	cil_list_destroy(&def->class_datums, CIL_FALSE);
+
+	free(def);
+}
+
+int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_handleunknown *unknown = NULL;
+	char *unknown_key;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_handleunknown_init(&unknown);
+
+	unknown_key = parse_current->next->data;
+	if (unknown_key == CIL_KEY_HANDLEUNKNOWN_ALLOW) {
+		unknown->handle_unknown = SEPOL_ALLOW_UNKNOWN;
+	} else if (unknown_key == CIL_KEY_HANDLEUNKNOWN_DENY) {
+		unknown->handle_unknown = SEPOL_DENY_UNKNOWN;
+	} else if (unknown_key == CIL_KEY_HANDLEUNKNOWN_REJECT) {
+		unknown->handle_unknown = SEPOL_REJECT_UNKNOWN;
+	} else {
+		cil_log(CIL_ERR, "Expected either \'%s\', \'%s\', or \'%s\'\n", CIL_KEY_HANDLEUNKNOWN_ALLOW, CIL_KEY_HANDLEUNKNOWN_DENY, CIL_KEY_HANDLEUNKNOWN_REJECT);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	ast_node->data = unknown;
+	ast_node->flavor = CIL_HANDLEUNKNOWN;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad handleunknown");
+	cil_destroy_handleunknown(unknown);
+	return rc;
+}
+
+void cil_destroy_handleunknown(struct cil_handleunknown *unk)
+{
+	free(unk);
+}
+
+int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	int rc = SEPOL_ERR;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+	struct cil_mls *mls = NULL;
+
+	if (parse_current == NULL || ast_node == NULL) {
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cil_mls_init(&mls);
+
+	if (parse_current->next->data == CIL_KEY_CONDTRUE) {
+		mls->value = CIL_TRUE;
+	} else if (parse_current->next->data == CIL_KEY_CONDFALSE) {
+		mls->value = CIL_FALSE;
+	} else {
+		cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	ast_node->data = mls;
+	ast_node->flavor = CIL_MLS;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad mls");
+	cil_destroy_mls(mls);
+	return rc;
+}
+
+void cil_destroy_mls(struct cil_mls *mls)
+{
+	free(mls);
+}
+
+int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	/* No need to check syntax, because this is auto generated */
+	struct cil_src_info *info = NULL;
+
+	cil_src_info_init(&info);
+
+	info->is_cil = (parse_current->next->data == CIL_KEY_SRC_CIL) ? CIL_TRUE : CIL_FALSE;
+	info->path = parse_current->next->next->data;
+
+	ast_node->data = info;
+	ast_node->flavor = CIL_SRC_INFO;
+
+	return SEPOL_OK;
+}
+
+void cil_destroy_src_info(struct cil_src_info *info)
+{
+	free(info);
+}
+
+int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args)
+{
+	struct cil_args_build *args = NULL;
+	struct cil_tree_node *ast_current = NULL;
+	struct cil_db *db = NULL;
+	struct cil_tree_node *ast_node = NULL;
+	struct cil_tree_node *macro = NULL;
+	struct cil_tree_node *boolif = NULL;
+	struct cil_tree_node *tunif = NULL;
+	struct cil_tree_node *in = NULL;
+	int rc = SEPOL_ERR;
+
+	if (parse_current == NULL || finished == NULL || extra_args == NULL) {
+		goto exit;
+	}
+
+	args = extra_args;
+	ast_current = args->ast;
+	db = args->db;
+	macro = args->macro;
+	boolif = args->boolif;
+	tunif = args->tunif;
+	in = args->in;
+
+	if (parse_current->parent->cl_head != parse_current) {
+		/* ignore anything that isn't following a parenthesis */
+		rc = SEPOL_OK;
+		goto exit;
+	} else if (parse_current->data == NULL) {
+		/* the only time parenthsis can immediately following parenthesis is if
+		 * the parent is the root node */
+		if (parse_current->parent->parent == NULL) {
+			rc = SEPOL_OK;
+		} else {
+			cil_tree_log(parse_current, CIL_ERR, "Keyword expected after open parenthesis");
+		}
+		goto exit;
+	}
+
+	if (macro != NULL) {
+		if (parse_current->data == CIL_KEY_MACRO ||
+			parse_current->data == CIL_KEY_TUNABLE ||
+			parse_current->data == CIL_KEY_IN ||
+			parse_current->data == CIL_KEY_BLOCK ||
+			parse_current->data == CIL_KEY_BLOCKINHERIT ||
+			parse_current->data == CIL_KEY_BLOCKABSTRACT) {
+			rc = SEPOL_ERR;
+			cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macros", (char *)parse_current->data);
+			goto exit;
+		}
+	}
+
+	if (boolif != NULL) {
+		if (parse_current->data != CIL_KEY_CONDTRUE &&
+			parse_current->data != CIL_KEY_CONDFALSE &&
+			parse_current->data != CIL_KEY_AUDITALLOW &&
+			parse_current->data != CIL_KEY_TUNABLEIF &&
+			parse_current->data != CIL_KEY_ALLOW &&
+			parse_current->data != CIL_KEY_DONTAUDIT &&
+			parse_current->data != CIL_KEY_TYPETRANSITION &&
+			parse_current->data != CIL_KEY_TYPECHANGE &&
+			parse_current->data != CIL_KEY_CALL) {
+			rc = SEPOL_ERR;
+			cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data);
+			if (((struct cil_booleanif*)boolif->data)->preserved_tunable) {
+				cil_log(CIL_ERR, "%s cannot be defined within tunableif statement (treated as a booleanif due to preserve-tunables)\n",
+						(char*)parse_current->data);
+			} else {
+				cil_log(CIL_ERR, "%s cannot be defined within booleanif statement\n",
+						(char*)parse_current->data);
+			}
+			goto exit;
+		}
+	}
+
+	if (tunif != NULL) {
+		if (parse_current->data == CIL_KEY_TUNABLE) {
+			rc = SEPOL_ERR;
+			cil_tree_log(parse_current, CIL_ERR, "Found tunable");
+			cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n");
+			goto exit;
+		}
+	}
+
+	if (in != NULL) {
+		if (parse_current->data == CIL_KEY_IN) {
+			rc = SEPOL_ERR;
+			cil_tree_log(parse_current, CIL_ERR, "Found in-statement");
+			cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n");
+			goto exit;
+		}
+	}
+
+	cil_tree_node_init(&ast_node);
+
+	ast_node->parent = ast_current;
+	ast_node->line = parse_current->line;
+	ast_node->hll_line = parse_current->hll_line;
+
+	if (parse_current->data == CIL_KEY_BLOCK) {
+		rc = cil_gen_block(db, parse_current, ast_node, 0);
+	} else if (parse_current->data == CIL_KEY_BLOCKINHERIT) {
+		rc = cil_gen_blockinherit(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_BLOCKABSTRACT) {
+		rc = cil_gen_blockabstract(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_IN) {
+		rc = cil_gen_in(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_CLASS) {
+		rc = cil_gen_class(db, parse_current, ast_node);
+		// To avoid parsing list of perms again
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CLASSORDER) {
+		rc = cil_gen_classorder(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_MAP_CLASS) {
+		rc = cil_gen_map_class(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CLASSMAPPING) {
+		rc = cil_gen_classmapping(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CLASSPERMISSION) {
+		rc = cil_gen_classpermission(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CLASSPERMISSIONSET) {
+		rc = cil_gen_classpermissionset(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_COMMON) {
+		rc = cil_gen_common(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CLASSCOMMON) {
+		rc = cil_gen_classcommon(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_SID) {
+		rc = cil_gen_sid(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SIDCONTEXT) {
+		rc = cil_gen_sidcontext(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SIDORDER) {
+		rc = cil_gen_sidorder(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_USER) {
+		rc = cil_gen_user(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_USERATTRIBUTE) {
+		rc = cil_gen_userattribute(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_USERATTRIBUTESET) {
+		rc = cil_gen_userattributeset(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_USERLEVEL) {
+		rc = cil_gen_userlevel(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_USERRANGE) {
+		rc = cil_gen_userrange(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_USERBOUNDS) {
+		rc = cil_gen_bounds(db, parse_current, ast_node, CIL_USER);
+	} else if (parse_current->data == CIL_KEY_USERPREFIX) {
+		rc = cil_gen_userprefix(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_SELINUXUSER) {
+		rc = cil_gen_selinuxuser(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SELINUXUSERDEFAULT) {
+		rc = cil_gen_selinuxuserdefault(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_TYPE) {
+		rc = cil_gen_type(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_TYPEATTRIBUTE) {
+		rc = cil_gen_typeattribute(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_TYPEATTRIBUTESET) {
+		rc = cil_gen_typeattributeset(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_TYPEALIAS) {
+		rc = cil_gen_alias(db, parse_current, ast_node, CIL_TYPEALIAS);
+	} else if (parse_current->data == CIL_KEY_TYPEALIASACTUAL) {
+		rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_TYPEALIASACTUAL);
+	} else if (parse_current->data == CIL_KEY_TYPEBOUNDS) {
+		rc = cil_gen_bounds(db, parse_current, ast_node, CIL_TYPE);
+	} else if (parse_current->data == CIL_KEY_TYPEPERMISSIVE) {
+		rc = cil_gen_typepermissive(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_RANGETRANSITION) {
+		rc = cil_gen_rangetransition(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_ROLE) {
+		rc = cil_gen_role(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_USERROLE) {
+		rc = cil_gen_userrole(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_ROLETYPE) {
+		rc = cil_gen_roletype(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_ROLETRANSITION) {
+		rc = cil_gen_roletransition(parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_ROLEALLOW) {
+		rc = cil_gen_roleallow(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_ROLEATTRIBUTE) {
+		rc = cil_gen_roleattribute(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_ROLEATTRIBUTESET) {
+		rc = cil_gen_roleattributeset(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_ROLEBOUNDS) {
+		rc = cil_gen_bounds(db, parse_current, ast_node, CIL_ROLE);
+	} else if (parse_current->data == CIL_KEY_BOOL) {
+		rc = cil_gen_bool(db, parse_current, ast_node, CIL_FALSE);
+	} else if (parse_current->data == CIL_KEY_BOOLEANIF) {
+		rc = cil_gen_boolif(db, parse_current, ast_node, CIL_FALSE);
+	} else if(parse_current->data == CIL_KEY_TUNABLE) {
+		if (db->preserve_tunables) {
+			rc = cil_gen_bool(db, parse_current, ast_node, CIL_TRUE);
+		} else {
+			rc = cil_gen_tunable(db, parse_current, ast_node);
+		}
+	} else if (parse_current->data == CIL_KEY_TUNABLEIF) {
+		if (db->preserve_tunables) {
+			rc = cil_gen_boolif(db, parse_current, ast_node, CIL_TRUE);
+		} else {
+			rc = cil_gen_tunif(db, parse_current, ast_node);
+		}
+	} else if (parse_current->data == CIL_KEY_CONDTRUE) {
+		rc = cil_gen_condblock(db, parse_current, ast_node, CIL_CONDTRUE);
+	} else if (parse_current->data == CIL_KEY_CONDFALSE) {
+		rc = cil_gen_condblock(db, parse_current, ast_node, CIL_CONDFALSE);
+	} else if (parse_current->data == CIL_KEY_ALLOW) {
+		rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_ALLOWED);
+		// So that the object and perms lists do not get parsed again
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_AUDITALLOW) {
+		rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_AUDITALLOW);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DONTAUDIT) {
+		rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_DONTAUDIT);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_NEVERALLOW) {
+		rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_ALLOWX) {
+		rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_ALLOWED);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_AUDITALLOWX) {
+		rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_AUDITALLOW);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DONTAUDITX) {
+		rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_DONTAUDIT);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_NEVERALLOWX) {
+		rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_PERMISSIONX) {
+		rc = cil_gen_permissionx(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_TYPETRANSITION) {
+		rc = cil_gen_typetransition(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_TYPECHANGE) {
+		rc = cil_gen_type_rule(parse_current, ast_node, CIL_TYPE_CHANGE);
+	} else if (parse_current->data == CIL_KEY_TYPEMEMBER) {
+		rc = cil_gen_type_rule(parse_current, ast_node, CIL_TYPE_MEMBER);
+	} else if (parse_current->data == CIL_KEY_SENSITIVITY) {
+		rc = cil_gen_sensitivity(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_SENSALIAS) {
+		rc = cil_gen_alias(db, parse_current, ast_node, CIL_SENSALIAS);
+	} else if (parse_current->data == CIL_KEY_SENSALIASACTUAL) {
+		rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_SENSALIASACTUAL);
+	} else if (parse_current->data == CIL_KEY_CATEGORY) {
+		rc = cil_gen_category(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_CATALIAS) {
+		rc = cil_gen_alias(db, parse_current, ast_node, CIL_CATALIAS);
+	} else if (parse_current->data == CIL_KEY_CATALIASACTUAL) {
+		rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_CATALIASACTUAL);
+	} else if (parse_current->data == CIL_KEY_CATSET) {
+		rc = cil_gen_catset(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CATORDER) {
+		rc = cil_gen_catorder(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SENSITIVITYORDER) {
+		rc = cil_gen_sensitivityorder(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SENSCAT) {
+		rc = cil_gen_senscat(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_LEVEL) {
+		rc = cil_gen_level(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_LEVELRANGE) {
+		rc = cil_gen_levelrange(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CONSTRAIN) {
+		rc = cil_gen_constrain(db, parse_current, ast_node, CIL_CONSTRAIN);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_MLSCONSTRAIN) {
+		rc = cil_gen_constrain(db, parse_current, ast_node, CIL_MLSCONSTRAIN);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_VALIDATETRANS) {
+		rc = cil_gen_validatetrans(db, parse_current, ast_node, CIL_VALIDATETRANS);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_MLSVALIDATETRANS) {
+		rc = cil_gen_validatetrans(db, parse_current, ast_node, CIL_MLSVALIDATETRANS);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_CONTEXT) {
+		rc = cil_gen_context(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_FILECON) {
+		rc = cil_gen_filecon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_PORTCON) {
+		rc = cil_gen_portcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_NODECON) {
+		rc = cil_gen_nodecon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_GENFSCON) {
+		rc = cil_gen_genfscon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_NETIFCON) {
+		rc = cil_gen_netifcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_PIRQCON) {
+		rc = cil_gen_pirqcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_IOMEMCON) {
+		rc = cil_gen_iomemcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_IOPORTCON) {
+		rc = cil_gen_ioportcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_PCIDEVICECON) {
+		rc = cil_gen_pcidevicecon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DEVICETREECON) {
+		rc = cil_gen_devicetreecon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_FSUSE) {
+		rc = cil_gen_fsuse(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_MACRO) {
+		rc = cil_gen_macro(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_CALL) {
+		rc = cil_gen_call(db, parse_current, ast_node);
+		*finished = 1;
+	} else if (parse_current->data == CIL_KEY_POLICYCAP) {
+		rc = cil_gen_policycap(db, parse_current, ast_node);
+		*finished = 1;
+	} else if (parse_current->data == CIL_KEY_OPTIONAL) {
+		rc = cil_gen_optional(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_IPADDR) {
+		rc = cil_gen_ipaddr(db, parse_current, ast_node);
+	} else if (parse_current->data == CIL_KEY_DEFAULTUSER) {
+		rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTUSER);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DEFAULTROLE) {
+		rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTROLE);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DEFAULTTYPE) {
+		rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTTYPE);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_DEFAULTRANGE) {
+		rc = cil_gen_defaultrange(parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_HANDLEUNKNOWN) {
+		rc = cil_gen_handleunknown(parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_MLS) {
+		rc = cil_gen_mls(parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_SRC_INFO) {
+		rc = cil_gen_src_info(parse_current, ast_node);
+	} else {
+		cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data);
+		rc = SEPOL_ERR;
+	}
+
+	if (rc == SEPOL_OK) {
+		if (ast_current->cl_head == NULL) {
+			if (ast_current->flavor == CIL_MACRO) {
+				args->macro = ast_current;
+			}
+
+			if (ast_current->flavor == CIL_BOOLEANIF) {
+				args->boolif = ast_current;
+			}
+
+			if (ast_current->flavor == CIL_TUNABLEIF) {
+				args->tunif = ast_current;
+			}
+
+			if (ast_current->flavor == CIL_IN) {
+				args->in = ast_current;
+			}
+
+			ast_current->cl_head = ast_node;
+		} else {
+			ast_current->cl_tail->next = ast_node;
+		}
+		ast_current->cl_tail = ast_node;
+		ast_current = ast_node;
+		args->ast = ast_current;
+	} else {
+		cil_tree_node_destroy(&ast_node);
+	}
+
+exit:
+	return rc;
+}
+
+int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *ast = NULL;
+	struct cil_args_build *args = NULL;
+
+	if (extra_args == NULL) {
+		goto exit;
+	}
+
+	args = extra_args;
+	ast = args->ast;
+
+	if (ast->flavor == CIL_ROOT) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	args->ast = ast->parent;
+
+	if (ast->flavor == CIL_MACRO) {
+		args->macro = NULL;
+	}
+
+	if (ast->flavor == CIL_BOOLEANIF) {
+		args->boolif = NULL;
+	}
+
+	if (ast->flavor == CIL_TUNABLEIF) {
+		args->tunif = NULL;
+	}
+
+	if (ast->flavor == CIL_IN) {
+		args->in = NULL;
+	}
+
+	// At this point we no longer have any need for parse_current or any of its
+	// siblings; they have all been converted to the appropriate AST node. The
+	// full parse tree will get deleted elsewhere, but in an attempt to
+	// minimize memory useage (of which the parse tree uses alot), start
+	// deleting the parts we don't need now.
+	cil_tree_children_destroy(parse_current->parent);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_build extra_args;
+
+	if (db == NULL || parse_tree == NULL || ast == NULL) {
+		goto exit;
+	}
+
+	extra_args.ast = ast;
+	extra_args.db = db;
+	extra_args.macro = NULL;
+	extra_args.boolif = NULL;
+	extra_args.tunif = NULL;
+	extra_args.in = NULL;
+
+	rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
new file mode 100644
index 0000000..825029e
--- /dev/null
+++ b/libsepol/cil/src/cil_build_ast.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_BUILD_AST_H_
+#define CIL_BUILD_AST_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor);
+int cil_parse_to_list(struct cil_tree_node *parse_cl_head, struct cil_list *ast_cl, enum cil_flavor flavor);
+
+int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract);
+void cil_destroy_block(struct cil_block *block);
+int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_blockinherit(struct cil_blockinherit *inherit);
+int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_blockabstract(struct cil_blockabstract *abstract);
+int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_in(struct cil_in *in);
+int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_class(struct cil_class *class);
+int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classorder(struct cil_classorder *classorder);
+int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
+void cil_destroy_perm(struct cil_perm *perm);
+int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
+int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perm_strs);
+int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp);
+void cil_destroy_classperms(struct cil_classperms *cp);
+void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set);
+void cil_destroy_classperms_set(struct cil_classperms_set *cp_set);
+int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **expr_list);
+void cil_destroy_classperms_list(struct cil_list **cp_list);
+int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classpermission(struct cil_classpermission *cp);
+int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classpermissionset(struct cil_classpermissionset *cps);
+int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classmapping(struct cil_classmapping *mapping);
+int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classcommon(struct cil_classcommon *clscom);
+int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sid(struct cil_sid *sid);
+int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sidcontext(struct cil_sidcontext *sidcon);
+int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sidorder(struct cil_sidorder *sidorder);
+int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_user(struct cil_user *user);
+int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userattribute(struct cil_userattribute *attr);
+int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userattributeset(struct cil_userattributeset *attrset);
+int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userlevel(struct cil_userlevel *usrlvl);
+int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userrange(struct cil_userrange *userrange);
+int cil_gen_userbounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userprefix(struct cil_userprefix *userprefix);
+int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser);
+int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_role(struct cil_role *role);
+int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roletype(struct cil_roletype *roletype);
+int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userrole(struct cil_userrole *userrole);
+int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roletransition(struct cil_roletransition *roletrans);
+int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleallow(struct cil_roleallow *roleallow);
+int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleattribute(struct cil_roleattribute *role);
+int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset);
+int cil_gen_rolebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+void cil_destroy_avrule(struct cil_avrule *rule);
+int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_permissionx(struct cil_permissionx *permx);
+int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+void cil_destroy_type_rule(struct cil_type_rule *rule);
+int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_type(struct cil_type *type);
+int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typeattribute(struct cil_typeattribute *type);
+int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif);
+void cil_destroy_bool(struct cil_bool *boolean);
+int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_tunable(struct cil_tunable *tunable);
+int cil_gen_constrain_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
+int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
+int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunable_if);
+void cil_destroy_boolif(struct cil_booleanif *bif);
+int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_tunif(struct cil_tunableif *tif);
+int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_condblock(struct cil_condblock *cb);
+int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_alias(struct cil_alias *alias);
+int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual);
+int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typeattributeset(struct cil_typeattributeset *attrtypes);
+int cil_gen_typebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typepermissive(struct cil_typepermissive *typeperm);
+int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_name(struct cil_name *name);
+void cil_destroy_typetransition(struct cil_nametypetransition *nametypetrans);
+int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_rangetransition(struct cil_rangetransition *rangetrans);
+int cil_gen_sensitivity(struct cil_db *idb, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sensitivity(struct cil_sens *sens);
+int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_category(struct cil_cat *cat);
+int cil_set_to_list(struct cil_tree_node *parse_current, struct cil_list *ast_cl);
+void cil_destroy_catset(struct cil_catset *catset);
+int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_catorder(struct cil_catorder *catorder);
+int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sensitivityorder(struct cil_sensorder *sensorder);
+int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_senscat(struct cil_senscat *senscat);
+int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_level(struct cil_level *level);
+int cil_fill_levelrange(struct cil_tree_node *low, struct cil_levelrange *lvlrange);
+int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_levelrange(struct cil_levelrange *lvlrange);
+void cil_destroy_constrain_node(struct cil_tree_node *cons_node);
+int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_constrain(struct cil_constrain *cons);
+int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_validatetrans(struct cil_validatetrans *validtrans);
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
+int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_context(struct cil_context *context);
+int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_filecon(struct cil_filecon *filecon);
+int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_portcon(struct cil_portcon *portcon);
+int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_nodecon(struct cil_nodecon *nodecon);
+int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_genfscon(struct cil_genfscon *genfscon);
+int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_netifcon(struct cil_netifcon *netifcon);
+int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_pirqcon(struct cil_pirqcon *pirqcon);
+int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_iomemcon(struct cil_iomemcon *iomemcon);
+int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ioportcon(struct cil_ioportcon *ioportcon);
+int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_pcidevicecon(struct cil_pcidevicecon *pcidevicecon);
+int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_devicetreecon(struct cil_devicetreecon *devicetreecon);
+int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_fsuse(struct cil_fsuse *fsuse);
+void cil_destroy_param(struct cil_param *param);
+int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_macro(struct cil_macro *macro);
+int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_call(struct cil_call *call);
+void cil_destroy_args(struct cil_args *args);
+int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_optional(struct cil_optional *optional);
+int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_policycap(struct cil_policycap *polcap);
+int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ipaddr(struct cil_ipaddr *ipaddr);
+int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_bounds(struct cil_bounds *bounds);
+int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_default(struct cil_default *def);
+int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_handleunknown(struct cil_handleunknown *unk);
+int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_mls(struct cil_mls *mls);
+int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_defaultrange(struct cil_defaultrange *def);
+int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_src_info(struct cil_src_info *info);
+
+int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats);
+void cil_destroy_cats(struct cil_cats *cats);
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
+int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer);
+int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer);
+int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr);
+int cil_fill_level(struct cil_tree_node *sens, struct cil_level *level);
+
+int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast);
+
+#endif /* CIL_BUILD_AST_H_ */
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
new file mode 100644
index 0000000..5debd0d
--- /dev/null
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -0,0 +1,2087 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+#include "cil_copy_ast.h"
+#include "cil_build_ast.h"
+#include "cil_strpool.h"
+
+struct cil_args_copy {
+	struct cil_tree_node *dest;
+	struct cil_db *db;
+};
+
+void cil_copy_list(struct cil_list *data, struct cil_list **copy)
+{
+	struct cil_list *new;
+	struct cil_list_item *orig_item;
+
+	cil_list_init(&new, data->flavor);
+
+	cil_list_for_each(orig_item, data) {
+		switch (orig_item->flavor) {
+		case CIL_STRING:
+			cil_list_append(new, CIL_STRING, orig_item->data);
+			break;
+		case CIL_LIST: {
+			struct cil_list *new_sub = NULL;
+			cil_copy_list((struct cil_list*)orig_item->data, &new_sub);
+			cil_list_append(new, CIL_LIST, new_sub);
+			break;
+		}
+		case CIL_PARAM: {
+			struct cil_param *po = orig_item->data;
+			struct cil_param *pn;
+			cil_param_init(&pn);
+			pn->str = po->str;
+			pn->flavor = po->flavor;
+			cil_list_append(new, CIL_PARAM, pn);
+		}
+			break;
+
+		default:
+			cil_list_append(new, orig_item->flavor, orig_item->data);
+			break;
+		}
+	}
+
+	*copy = new;
+}
+
+int cil_copy_node(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	char *new = NULL;
+
+	if (data != NULL) {
+		new = data;
+	}
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_block(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_block *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_block *new;
+		cil_block_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_blockabstract(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_blockabstract *orig = data;
+	struct cil_blockabstract *new = NULL;
+
+	cil_blockabstract_init(&new);
+
+	new->block_str = orig->block_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_blockinherit(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_blockinherit *orig = data;
+	struct cil_blockinherit *new = NULL;
+
+	cil_blockinherit_init(&new);
+
+	new->block_str = orig->block_str;
+	new->block = orig->block;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_policycap(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_policycap *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_policycap *new;
+		cil_policycap_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_perm(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_perm *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_perm *new;
+		cil_perm_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+void cil_copy_classperms(struct cil_classperms *orig, struct cil_classperms **new)
+{
+	cil_classperms_init(new);
+	(*new)->class_str = orig->class_str;
+	cil_copy_list(orig->perm_strs, &((*new)->perm_strs));
+}
+
+void cil_copy_classperms_set(struct cil_classperms_set *orig, struct cil_classperms_set **new)
+{
+	cil_classperms_set_init(new);
+	(*new)->set_str = orig->set_str;
+}
+
+void cil_copy_classperms_list(struct cil_list *orig, struct cil_list **new)
+{
+	struct cil_list_item *orig_item;
+
+	if (orig == NULL) {
+		return;
+	}
+
+	cil_list_init(new, CIL_LIST_ITEM);
+	cil_list_for_each(orig_item, orig) {
+		if (orig_item->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp;
+			cil_copy_classperms(orig_item->data, &cp);
+			cil_list_append(*new, CIL_CLASSPERMS, cp);
+		} else {
+			struct cil_classperms_set *cp_set;
+			cil_copy_classperms_set(orig_item->data, &cp_set);
+			cil_list_append(*new, CIL_CLASSPERMS_SET, cp_set);
+		}
+	}
+}
+
+int cil_copy_classmapping(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_classmapping *orig = data;
+	struct cil_classmapping *new = NULL;
+
+	cil_classmapping_init(&new);
+
+	new->map_class_str = orig->map_class_str;
+	new->map_perm_str = orig->map_perm_str;
+
+	cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_class(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_class *orig = data;
+	struct cil_class *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_class: class cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_class_init(&new);
+
+	new->common = NULL;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_classorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_classorder *orig = data;
+	struct cil_classorder *new = NULL;
+
+	cil_classorder_init(&new);
+	if (orig->class_list_str != NULL) {
+		cil_copy_list(orig->class_list_str, &new->class_list_str);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_classpermission *orig = data;
+	struct cil_classpermission *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	if (key != NULL) {
+		cil_symtab_get_datum(symtab, key, &datum);
+		if (datum != NULL) {
+			cil_log(CIL_INFO, "classpermission cannot be redefined\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	cil_classpermission_init(&new);
+
+	cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void *data, void **copy,  __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_classpermissionset *orig = data;
+	struct cil_classpermissionset *new = NULL;
+
+	cil_classpermissionset_init(&new);
+
+	new->set_str = orig->set_str;
+
+	cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_classcommon(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_classcommon *orig = data;
+	struct cil_classcommon *new = NULL;
+
+	cil_classcommon_init(&new);
+
+	new->class_str = orig->class_str;
+	new->common_str = orig->common_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_sid(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_sid *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_sid *new;
+		cil_sid_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_sidcontext *orig = data;
+	struct cil_sidcontext *new = NULL;
+
+	cil_sidcontext_init(&new);
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_sidorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_sidorder *orig = data;
+	struct cil_sidorder *new = NULL;
+
+	cil_sidorder_init(&new);
+	if (orig->sid_list_str != NULL) {
+		cil_copy_list(orig->sid_list_str, &new->sid_list_str);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_user(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_user *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_user *new;
+		cil_user_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_userattribute *orig = data;
+	struct cil_userattribute *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		cil_userattribute_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_userattributeset *orig = data;
+	struct cil_userattributeset *new = NULL;
+
+	cil_userattributeset_init(&new);
+
+	new->attr_str = orig->attr_str;
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userrole(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_userrole *orig = data;
+	struct cil_userrole *new = NULL;
+
+	cil_userrole_init(&new);
+
+	new->user_str = orig->user_str;
+	new->role_str = orig->role_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_userlevel *orig = data;
+	struct cil_userlevel *new = NULL;
+
+	cil_userlevel_init(&new);
+
+	new->user_str = orig->user_str;
+
+	if (orig->level_str != NULL) {
+		new->level_str = orig->level_str;
+	} else {
+		cil_copy_fill_level(db, orig->level, &new->level);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userrange(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_userrange *orig = data;
+	struct cil_userrange *new = NULL;
+
+	cil_userrange_init(&new);
+
+	new->user_str = orig->user_str;
+
+	if (orig->range_str != NULL) {
+		new->range_str = orig->range_str;
+	} else {
+		cil_levelrange_init(&new->range);
+		cil_copy_fill_levelrange(db, orig->range, new->range);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_userprefix(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_userprefix *orig = data;
+	struct cil_userprefix *new = NULL;
+
+	cil_userprefix_init(&new);
+
+	new->user_str = orig->user_str;
+	new->prefix_str = orig->prefix_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_role(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_role *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_role *new;
+		cil_role_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_roletype(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_roletype *orig = data;
+	struct cil_roletype *new = NULL;
+
+	cil_roletype_init(&new);
+
+	new->role_str = orig->role_str;
+	new->type_str = orig->type_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_roleattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_roleattribute *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_roleattribute *new;
+		cil_roleattribute_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_roleattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_roleattributeset *orig = data;
+	struct cil_roleattributeset *new = NULL;
+
+	cil_roleattributeset_init(&new);
+
+	new->attr_str = orig->attr_str;
+	
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_roleallow(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_roleallow *orig = data;
+	struct cil_roleallow *new = NULL;
+
+	cil_roleallow_init(&new);
+
+	new->src_str = orig->src_str;
+	new->tgt_str = orig->tgt_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_type(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_type *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_type *new;
+		cil_type_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_typepermissive(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_typepermissive *orig = data;
+	struct cil_typepermissive *new = NULL;
+
+	cil_typepermissive_init(&new);
+
+	new->type_str = orig->type_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_typeattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_typeattribute *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_typeattribute *new;
+		cil_typeattribute_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_typeattributeset *orig = data;
+	struct cil_typeattributeset *new = NULL;
+
+	cil_typeattributeset_init(&new);
+
+	new->attr_str = orig->attr_str;
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_alias *orig = data;
+	struct cil_alias *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_alias: alias cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_alias_init(&new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_aliasactual(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused))symtab_t *symtab)
+{
+	struct cil_aliasactual *orig = data;
+	struct cil_aliasactual *new = NULL;
+
+	cil_aliasactual_init(&new);
+
+	new->alias_str = orig->alias_str;
+	new->actual_str = orig->actual_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_roletransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_roletransition *orig = data;
+	struct cil_roletransition *new = NULL;
+
+	cil_roletransition_init(&new);
+
+	new->src_str = orig->src_str;
+	new->tgt_str = orig->tgt_str;
+	new->obj_str = orig->obj_str;
+	new->result_str = orig->result_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_nametypetransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_nametypetransition *orig = data;
+	struct cil_nametypetransition *new = NULL;
+
+	cil_nametypetransition_init(&new);
+
+	new->src_str = orig->src_str;
+	new->tgt_str = orig->tgt_str;
+	new->obj_str = orig->obj_str;
+	new->name_str = orig->name_str;
+	new->result_str = orig->result_str;
+
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_rangetransition(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_rangetransition *orig = data;
+	struct cil_rangetransition *new = NULL;
+
+	cil_rangetransition_init(&new);
+
+	new->src_str = orig->src_str;
+	new->exec_str = orig->exec_str;
+	new->obj_str = orig->obj_str;
+
+	if (orig->range_str != NULL) {
+		new->range_str = orig->range_str;
+	} else {
+		cil_levelrange_init(&new->range);
+		cil_copy_fill_levelrange(db, orig->range, new->range);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_bool(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_bool *orig = data;
+	struct cil_bool *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_bool: boolean cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_bool_init(&new);
+	new->value = orig->value;
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_tunable(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_tunable *orig = data;
+	struct cil_tunable *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_tunable: tunable cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_tunable_init(&new);
+	new->value = orig->value;
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+void cil_copy_fill_permissionx(struct cil_db *db, struct cil_permissionx *orig, struct cil_permissionx *new)
+{
+	new->kind = orig->kind;
+	new->obj_str = orig->obj_str;
+	cil_copy_expr(db, orig->expr_str, &new->expr_str);
+}
+
+int cil_copy_avrule(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_avrule *orig = data;
+	struct cil_avrule *new = NULL;
+
+	cil_avrule_init(&new);
+
+	new->is_extended = orig->is_extended;
+	new->rule_kind = orig->rule_kind;
+	new->src_str = orig->src_str;
+	new->tgt_str = orig->tgt_str;
+
+	if (!new->is_extended) {
+		cil_copy_classperms_list(orig->perms.classperms, &new->perms.classperms);
+	} else {
+		if (new->perms.x.permx_str != NULL) {
+			new->perms.x.permx_str = orig->perms.x.permx_str;
+		} else {
+			cil_permissionx_init(&new->perms.x.permx);
+			cil_copy_fill_permissionx(db, orig->perms.x.permx, new->perms.x.permx);
+		}
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_permissionx(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_permissionx *orig = data;
+	struct cil_permissionx *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_permissionx: permissionx cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_permissionx_init(&new);
+	cil_copy_fill_permissionx(db, orig, new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_type_rule(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_type_rule  *orig = data;
+	struct cil_type_rule *new = NULL;
+
+	cil_type_rule_init(&new);
+
+	new->rule_kind = orig->rule_kind;
+	new->src_str = orig->src_str;
+	new->tgt_str = orig->tgt_str;
+	new->obj_str = orig->obj_str;
+	new->result_str = orig->result_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_sens(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_sens *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_sens *new;
+		cil_sens_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_cat(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_cat *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_cat *new;
+		cil_cat_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+void cil_copy_cats(struct cil_db *db, struct cil_cats *orig, struct cil_cats **new)
+{
+	cil_cats_init(new);
+	cil_copy_expr(db, orig->str_expr, &(*new)->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &(*new)->datum_expr);
+}
+
+int cil_copy_catset(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_catset *orig = data;
+	struct cil_catset *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_catset: categoryset cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_catset_init(&new);
+
+	cil_copy_cats(db, orig->cats, &new->cats);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_senscat(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_senscat *orig = data;
+	struct cil_senscat *new = NULL;
+
+	cil_senscat_init(&new);
+
+	new->sens_str = orig->sens_str;
+
+	cil_copy_cats(db, orig->cats, &new->cats);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_catorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_catorder *orig = data;
+	struct cil_catorder *new = NULL;
+
+	cil_catorder_init(&new);
+	if (orig->cat_list_str != NULL) {
+		cil_copy_list(orig->cat_list_str, &new->cat_list_str);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_sensitivityorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_sensorder *orig = data;
+	struct cil_sensorder *new = NULL;
+
+	cil_sensorder_init(&new);
+	if (orig->sens_list_str != NULL) {
+		cil_copy_list(orig->sens_list_str, &new->sens_list_str);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+void cil_copy_fill_level(struct cil_db *db, struct cil_level *orig, struct cil_level **new)
+{
+	cil_level_init(new);
+
+	(*new)->sens_str = orig->sens_str;
+
+	if (orig->cats != NULL) {
+		cil_copy_cats(db, orig->cats, &(*new)->cats);
+	}
+}
+
+int cil_copy_level(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_level *orig = data;
+	struct cil_level *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	if (key != NULL) {
+		cil_symtab_get_datum(symtab, key, &datum);
+		if (datum != NULL) {
+			cil_log(CIL_INFO, "cil_copy_level: level cannot be redefined\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	cil_copy_fill_level(db, orig, &new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+void cil_copy_fill_levelrange(struct cil_db *db, struct cil_levelrange *data, struct cil_levelrange *new)
+{
+	if (data->low_str != NULL) {
+		new->low_str = data->low_str;
+	} else {
+		cil_copy_fill_level(db, data->low, &new->low);
+	}
+
+	if (data->high_str != NULL) {
+		new->high_str = data->high_str;
+	} else {
+		cil_copy_fill_level(db, data->high, &new->high);
+	}
+}
+
+int cil_copy_levelrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_levelrange *orig = data;
+	struct cil_levelrange *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	if (key != NULL) {
+		cil_symtab_get_datum(symtab, key, &datum);
+		if (datum != NULL) {
+			cil_log(CIL_INFO, "cil_copy_levelrange: levelrange cannot be redefined\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	cil_levelrange_init(&new);
+	cil_copy_fill_levelrange(db, orig, new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+void cil_copy_fill_context(struct cil_db *db, struct cil_context *data, struct cil_context *new)
+{
+	new->user_str = data->user_str;
+	new->role_str = data->role_str;
+	new->type_str = data->type_str;
+
+	if (data->range_str != NULL) {
+		new->range_str = data->range_str;
+	} else {
+		cil_levelrange_init(&new->range);
+		cil_copy_fill_levelrange(db, data->range, new->range);
+	}
+}
+
+int cil_copy_context(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_context *orig = data;
+	struct cil_context *new = NULL;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	if (key != NULL) {
+		cil_symtab_get_datum(symtab, key, &datum);
+		if (datum != NULL) {
+			cil_log(CIL_INFO, "cil_copy_context: context cannot be redefined\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	cil_context_init(&new);
+	cil_copy_fill_context(db, orig, new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_netifcon *orig = data;
+	struct cil_netifcon *new = NULL;
+
+	cil_netifcon_init(&new);
+
+	new->interface_str = orig->interface_str;
+
+	if (orig->if_context_str != NULL) {
+		new->if_context_str = orig->if_context_str;
+	} else {
+		cil_context_init(&new->if_context);
+		cil_copy_fill_context(db, orig->if_context, new->if_context);
+	}
+
+	if (orig->packet_context_str != NULL) {
+		new->packet_context_str = orig->packet_context_str;
+	} else {
+		cil_context_init(&new->packet_context);
+		cil_copy_fill_context(db, orig->packet_context, new->packet_context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_genfscon *orig = data;
+	struct cil_genfscon *new = NULL;
+
+	cil_genfscon_init(&new);
+
+	new->fs_str = orig->fs_str;
+	new->path_str = orig->path_str;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_filecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_filecon *orig = data;
+	struct cil_filecon *new = NULL;
+
+	cil_filecon_init(&new);
+
+	new->path_str = orig->path_str;
+	new->type = orig->type;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else if (orig->context != NULL) {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_nodecon *orig = data;
+	struct cil_nodecon *new = NULL;
+
+	cil_nodecon_init(&new);
+
+	if (orig->addr_str != NULL) {
+		new->addr_str = orig->addr_str;
+	} else {
+		cil_ipaddr_init(&new->addr);
+		cil_copy_fill_ipaddr(orig->addr, new->addr);
+	}
+
+	if (orig->mask_str != NULL) {
+		new->mask_str = orig->mask_str;
+	} else {
+		cil_ipaddr_init(&new->mask);
+		cil_copy_fill_ipaddr(orig->mask, new->mask);
+	}
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_portcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_portcon *orig = data;
+	struct cil_portcon *new = NULL;
+
+	cil_portcon_init(&new);
+
+	new->proto = orig->proto;
+	new->port_low = orig->port_low;
+	new->port_high = orig->port_high;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_pirqcon *orig = data;
+	struct cil_pirqcon *new = NULL;
+
+	cil_pirqcon_init(&new);
+
+	new->pirq = orig->pirq;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_iomemcon *orig = data;
+	struct cil_iomemcon *new = NULL;
+
+	cil_iomemcon_init(&new);
+
+	new->iomem_low = orig->iomem_low;
+	new->iomem_high = orig->iomem_high;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_ioportcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_ioportcon *orig = data;
+	struct cil_ioportcon *new = NULL;
+
+	cil_ioportcon_init(&new);
+
+	new->ioport_low = orig->ioport_low;
+	new->ioport_high = orig->ioport_high;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_pcidevicecon *orig = data;
+	struct cil_pcidevicecon *new = NULL;
+
+	cil_pcidevicecon_init(&new);
+
+	new->dev = orig->dev;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_devicetreecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_devicetreecon *orig = data;
+	struct cil_devicetreecon *new = NULL;
+
+	cil_devicetreecon_init(&new);
+
+	new->path = orig->path;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_fsuse(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_fsuse *orig = data;
+	struct cil_fsuse *new = NULL;
+
+	cil_fsuse_init(&new);
+
+	new->type = orig->type;
+	new->fs_str = orig->fs_str;
+
+	if (orig->context_str != NULL) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_expr(struct cil_db *db, struct cil_list *orig, struct cil_list **new)
+{
+	struct cil_list_item *curr;
+
+	if (orig == NULL) {
+		*new = NULL;
+		return SEPOL_OK;
+	}
+
+	cil_list_init(new, orig->flavor);
+
+	cil_list_for_each(curr, orig) {
+		switch (curr->flavor) {
+		case CIL_LIST: {
+			struct cil_list *sub_list;
+			cil_copy_expr(db, curr->data, &sub_list);
+			cil_list_append(*new, CIL_LIST, sub_list);
+			break;
+		}
+		case CIL_STRING:
+			cil_list_append(*new, CIL_STRING, curr->data);
+			break;
+		case CIL_DATUM:
+			cil_list_append(*new, curr->flavor, curr->data);
+			break;
+		case CIL_OP:
+			cil_list_append(*new, curr->flavor, curr->data);
+			break;
+		case CIL_CONS_OPERAND:
+			cil_list_append(*new, curr->flavor, curr->data);
+			break;
+		default:
+			cil_log(CIL_INFO, "Unknown flavor %d in expression being copied\n",curr->flavor);
+			cil_list_append(*new, curr->flavor, curr->data);
+			break;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_copy_constrain(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_constrain *orig = data;
+	struct cil_constrain *new = NULL;
+
+	cil_constrain_init(&new);
+	cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_validatetrans(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_validatetrans *orig = data;
+	struct cil_validatetrans *new = NULL;
+
+	cil_validatetrans_init(&new);
+
+	new->class_str = orig->class_str;
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_call(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_call *orig = data;
+	struct cil_call *new = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_call_init(&new);
+
+	new->macro_str = orig->macro_str;
+	new->macro = orig->macro;
+
+	if (orig->args_tree != NULL) {
+		cil_tree_init(&new->args_tree);
+		rc = cil_copy_ast(db, orig->args_tree->root, new->args_tree->root);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+	
+	new->copied = orig->copied;
+
+	*copy = new;
+
+	return SEPOL_OK;
+
+exit:
+	cil_destroy_call(new);
+	return rc;
+}
+
+int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_macro *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_macro *new;
+		cil_macro_init(&new);
+		if (orig->params != NULL) {
+			cil_copy_list(orig->params, &new->params);
+		}
+
+		*copy = new;
+
+	} else {
+		struct cil_list_item *curr_orig = NULL;
+		struct cil_list_item *curr_new = NULL;
+		struct cil_param *param_orig = NULL;
+		struct cil_param *param_new = NULL;
+
+		if (((struct cil_macro*)datum)->params != NULL) {
+			curr_new = ((struct cil_macro*)datum)->params->head;
+		}
+
+		if (orig->params != NULL) {
+			curr_orig = orig->params->head;
+		}
+
+		if (curr_orig != NULL && curr_new != NULL) {
+			while (curr_orig != NULL) {
+				if (curr_new == NULL) {
+					goto exit;
+				}
+
+				param_orig = (struct cil_param*)curr_orig->data;
+				param_new = (struct cil_param*)curr_new->data;
+				if (param_orig->str != param_new->str) {
+					goto exit;
+				} else if (param_orig->flavor != param_new->flavor) {
+					goto exit;
+				}
+
+				curr_orig = curr_orig->next;
+				curr_new = curr_new->next;
+			}
+
+			if (curr_new != NULL) {
+				goto exit;
+			}
+		} else if (!(curr_orig == NULL && curr_new == NULL)) {
+			goto exit;
+		}
+
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_INFO, "cil_copy_macro: macro cannot be redefined\n");
+	return SEPOL_ERR;
+}
+
+int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_optional *orig = data;
+	char *key = orig->datum.name;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum == NULL) {
+		struct cil_optional *new;
+		cil_optional_init(&new);
+		*copy = new;
+	} else {
+		*copy = datum;
+	}
+
+	return SEPOL_OK;
+}
+
+void cil_copy_fill_ipaddr(struct cil_ipaddr *data, struct cil_ipaddr *new)
+{
+	new->family = data->family;
+	memcpy(&new->ip, &data->ip, sizeof(data->ip));
+}
+
+int cil_copy_ipaddr(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+	struct cil_ipaddr *orig = data;
+	struct cil_ipaddr *new = NULL;
+	char * key = orig->datum.name;	
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		cil_log(CIL_INFO, "cil_copy_ipaddr: ipaddress cannot be redefined\n");
+		return SEPOL_ERR;
+	}
+
+	cil_ipaddr_init(&new);
+	cil_copy_fill_ipaddr(orig, new);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_condblock(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_condblock *orig = data;
+	struct cil_condblock *new = *copy;
+	cil_condblock_init(&new);
+	new->flavor = orig->flavor;
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_boolif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_booleanif *orig = data;
+	struct cil_booleanif *new = NULL;
+
+	cil_boolif_init(&new);
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+	new->preserved_tunable = orig->preserved_tunable;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_tunif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_tunableif *orig = data;
+	struct cil_tunableif *new = NULL;
+
+	cil_tunif_init(&new);
+
+	cil_copy_expr(db, orig->str_expr, &new->str_expr);
+	cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_default(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_default *orig = data;
+	struct cil_default *new = NULL;
+
+	cil_default_init(&new);
+
+	new->flavor = orig->flavor;
+
+	if (orig->class_strs != NULL) {
+		cil_copy_list(orig->class_strs, &new->class_strs);
+	}
+
+	new->object = orig->object;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_defaultrange(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_defaultrange *orig = data;
+	struct cil_defaultrange *new = NULL;
+
+	cil_defaultrange_init(&new);
+
+	if (orig->class_strs != NULL) {
+		cil_copy_list(orig->class_strs, &new->class_strs);
+	}
+
+	new->object_range = orig->object_range;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_handleunknown(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_handleunknown *orig = data;
+	struct cil_handleunknown *new = NULL;
+
+	cil_handleunknown_init(&new);
+	new->handle_unknown = orig->handle_unknown;
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_mls(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_mls *orig = data;
+	struct cil_mls *new = NULL;
+
+	cil_mls_init(&new);
+	new->value = orig->value;
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_bounds *orig = data;
+	struct cil_bounds *new = NULL;
+
+	cil_bounds_init(&new);
+
+	new->parent_str = orig->parent_str;
+	new->child_str = orig->child_str;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_src_info *orig = data;
+	struct cil_src_info *new = NULL;
+
+	cil_src_info_init(&new);
+
+	new->is_cil = orig->is_cil;
+	new->path = orig->path;
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
+int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *parent = NULL;
+	struct cil_tree_node *new = NULL;
+	struct cil_db *db = NULL;
+	struct cil_args_copy *args = NULL;
+	struct cil_tree_node *namespace = NULL;
+	struct cil_param *param = NULL;
+	enum cil_sym_index sym_index = CIL_SYM_UNKNOWN;
+	symtab_t *symtab = NULL;
+	void *data = NULL;
+	int (*copy_func)(struct cil_db *db, void *data, void **copy, symtab_t *symtab) = NULL;
+	struct cil_blockinherit *blockinherit = NULL;
+
+	if (orig == NULL || extra_args == NULL) {
+		goto exit;
+	}
+
+	args = extra_args;
+	parent = args->dest;
+	db = args->db;
+
+
+	switch (orig->flavor) {
+	case CIL_BLOCK:
+		copy_func = &cil_copy_block;
+		break;
+	case CIL_BLOCKABSTRACT:
+		copy_func = &cil_copy_blockabstract;
+		break;
+	case CIL_BLOCKINHERIT:
+		copy_func = &cil_copy_blockinherit;
+		break;
+	case CIL_POLICYCAP:
+		copy_func = &cil_copy_policycap;
+		break;
+	case CIL_PERM:
+	case CIL_MAP_PERM:
+		copy_func = &cil_copy_perm;
+		break;
+	case CIL_CLASSMAPPING:
+		copy_func = &cil_copy_classmapping;
+		break;
+	case CIL_CLASS:
+	case CIL_COMMON:
+	case CIL_MAP_CLASS:
+		copy_func = &cil_copy_class;
+		break;
+	case CIL_CLASSORDER:
+		copy_func = &cil_copy_classorder;
+		break;
+	case CIL_CLASSPERMISSION:
+		copy_func = &cil_copy_classpermission;
+		break;
+	case CIL_CLASSPERMISSIONSET:
+		copy_func = &cil_copy_classpermissionset;
+		break;
+	case CIL_CLASSCOMMON:
+		copy_func = &cil_copy_classcommon;
+		break;
+	case CIL_SID:
+		copy_func = &cil_copy_sid;
+		break;
+	case CIL_SIDCONTEXT:
+		copy_func = &cil_copy_sidcontext;
+		break;
+	case CIL_SIDORDER:
+		copy_func = &cil_copy_sidorder;
+		break;
+	case CIL_USER:
+		copy_func = &cil_copy_user;
+		break;
+	case CIL_USERATTRIBUTE:
+		copy_func = &cil_copy_userattribute;
+		break;
+	case CIL_USERATTRIBUTESET:
+		copy_func = &cil_copy_userattributeset;
+		break;
+	case CIL_USERROLE:
+		copy_func = &cil_copy_userrole;
+		break;
+	case CIL_USERLEVEL:
+		copy_func = &cil_copy_userlevel;
+		break;
+	case CIL_USERRANGE:
+		copy_func = &cil_copy_userrange;
+		break;
+	case CIL_USERBOUNDS:
+		copy_func = &cil_copy_bounds;
+		break;
+	case CIL_USERPREFIX:
+		copy_func = &cil_copy_userprefix;
+		break;
+	case CIL_ROLE:
+		copy_func = &cil_copy_role;
+		break;
+	case CIL_ROLETYPE:
+		copy_func = &cil_copy_roletype;
+		break;
+	case CIL_ROLEBOUNDS:
+		copy_func = &cil_copy_bounds;
+		break;
+	case CIL_ROLEATTRIBUTE:
+		copy_func = &cil_copy_roleattribute;
+		break;
+	case CIL_ROLEATTRIBUTESET:
+		copy_func = &cil_copy_roleattributeset;
+		break;
+	case CIL_ROLEALLOW:
+		copy_func = &cil_copy_roleallow;
+		break;
+	case CIL_TYPE:
+		copy_func = &cil_copy_type;
+		break;
+	case CIL_TYPEBOUNDS:
+		copy_func = &cil_copy_bounds;
+		break;
+	case CIL_TYPEPERMISSIVE:
+		copy_func = cil_copy_typepermissive;
+		break;
+	case CIL_TYPEATTRIBUTE:
+		copy_func = &cil_copy_typeattribute;
+		break;
+	case CIL_TYPEATTRIBUTESET:
+		copy_func = &cil_copy_typeattributeset;
+		break;
+	case CIL_TYPEALIAS:
+		copy_func = &cil_copy_alias;
+		break;
+	case CIL_TYPEALIASACTUAL:
+		copy_func = &cil_copy_aliasactual;
+		break;
+	case CIL_ROLETRANSITION:
+		copy_func = &cil_copy_roletransition;
+		break;
+	case CIL_NAMETYPETRANSITION:
+		copy_func = &cil_copy_nametypetransition;
+		break;
+	case CIL_RANGETRANSITION:
+		copy_func = &cil_copy_rangetransition;
+		break;
+	case CIL_TUNABLE:
+		copy_func = &cil_copy_tunable;
+		break;
+	case CIL_BOOL:
+		copy_func = &cil_copy_bool;
+		break;
+	case CIL_AVRULE:
+	case CIL_AVRULEX:
+		copy_func = &cil_copy_avrule;
+		break;
+	case CIL_PERMISSIONX:
+		copy_func = &cil_copy_permissionx;
+		break;
+	case CIL_TYPE_RULE:
+		copy_func = &cil_copy_type_rule;
+		break;
+	case CIL_SENS:
+		copy_func = &cil_copy_sens;
+		break;
+	case CIL_SENSALIAS:
+		copy_func = &cil_copy_alias;
+		break;
+	case CIL_SENSALIASACTUAL:
+		copy_func = &cil_copy_aliasactual;
+		break;
+	case CIL_CAT:
+		copy_func = &cil_copy_cat;
+		break;
+	case CIL_CATALIAS:
+		copy_func = &cil_copy_alias;
+		break;
+	case CIL_CATALIASACTUAL:
+		copy_func = &cil_copy_aliasactual;
+		break;
+	case CIL_CATSET:
+		copy_func = &cil_copy_catset;
+		break;
+	case CIL_SENSCAT:
+		copy_func = &cil_copy_senscat;
+		break;
+	case CIL_CATORDER:
+		copy_func = &cil_copy_catorder;
+		break;
+	case CIL_SENSITIVITYORDER:
+		copy_func = &cil_copy_sensitivityorder;
+		break;
+	case CIL_LEVEL:
+		copy_func = &cil_copy_level;
+		break;
+	case CIL_LEVELRANGE:
+		copy_func = &cil_copy_levelrange;
+		break;
+	case CIL_CONTEXT:
+		copy_func = &cil_copy_context;
+		break;
+	case CIL_NETIFCON:
+		copy_func = &cil_copy_netifcon;
+		break;
+	case CIL_GENFSCON:
+		copy_func = &cil_copy_genfscon;
+		break;
+	case CIL_FILECON:
+		copy_func = &cil_copy_filecon;
+		break;
+	case CIL_NODECON:
+		copy_func = &cil_copy_nodecon;
+		break;
+	case CIL_PORTCON:
+		copy_func = &cil_copy_portcon;
+		break;
+	case CIL_PIRQCON:
+		copy_func = &cil_copy_pirqcon;
+		break;
+	case CIL_IOMEMCON:
+		copy_func = &cil_copy_iomemcon;
+		break;
+	case CIL_IOPORTCON:
+		copy_func = &cil_copy_ioportcon;
+		break;
+	case CIL_PCIDEVICECON:
+		copy_func = &cil_copy_pcidevicecon;
+		break;
+	case CIL_DEVICETREECON:
+		copy_func = &cil_copy_devicetreecon;
+		break;
+	case CIL_FSUSE:
+		copy_func = &cil_copy_fsuse;
+		break;
+	case CIL_CONSTRAIN:
+	case CIL_MLSCONSTRAIN:
+		copy_func = &cil_copy_constrain;
+		break;
+	case CIL_VALIDATETRANS:
+	case CIL_MLSVALIDATETRANS:
+		copy_func = &cil_copy_validatetrans;
+		break;
+	case CIL_CALL:
+		copy_func = &cil_copy_call;
+		break;
+	case CIL_MACRO:
+		copy_func = &cil_copy_macro;
+		break;
+	case CIL_NODE:
+		copy_func = &cil_copy_node;
+		break;
+	case CIL_OPTIONAL:
+		copy_func = &cil_copy_optional;
+		break;
+	case CIL_IPADDR:
+		copy_func = &cil_copy_ipaddr;
+		break;
+	case CIL_CONDBLOCK:
+		copy_func = &cil_copy_condblock;
+		break;
+	case CIL_BOOLEANIF:
+		copy_func = &cil_copy_boolif;
+		break;
+	case CIL_TUNABLEIF:
+		copy_func = &cil_copy_tunif;
+		break;
+	case CIL_DEFAULTUSER:
+	case CIL_DEFAULTROLE:
+	case CIL_DEFAULTTYPE:
+		copy_func = &cil_copy_default;
+		break;
+	case CIL_DEFAULTRANGE:
+		copy_func = &cil_copy_defaultrange;
+		break;
+	case CIL_HANDLEUNKNOWN:
+		copy_func = &cil_copy_handleunknown;
+		break;
+	case CIL_MLS:
+		copy_func = &cil_copy_mls;
+		break;
+	case CIL_SRC_INFO:
+		copy_func = &cil_copy_src_info;
+		break;
+	default:
+		goto exit;
+	}
+
+	if (orig->flavor >= CIL_MIN_DECLARATIVE) {
+		rc = cil_flavor_to_symtab_index(orig->flavor, &sym_index);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_get_symtab(parent, &symtab, sym_index);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = (*copy_func)(db, orig->data, &data, symtab);
+	if (rc == SEPOL_OK) {
+		cil_tree_node_init(&new);
+
+		new->parent = parent;
+		new->line = orig->line;
+		new->hll_line = orig->hll_line;
+		new->flavor = orig->flavor;
+		new->data = data;
+
+		if (orig->flavor >= CIL_MIN_DECLARATIVE) {
+			rc = cil_symtab_insert(symtab, ((struct cil_symtab_datum*)orig->data)->name, ((struct cil_symtab_datum*)data), new);
+
+			namespace = new;
+			while (namespace->flavor != CIL_MACRO && namespace->flavor != CIL_BLOCK && namespace->flavor != CIL_ROOT) {
+				namespace = namespace->parent;
+			}
+
+			if (namespace->flavor == CIL_MACRO) {
+				struct cil_macro *macro = namespace->data;
+				struct cil_list *param_list = macro->params;
+				if (param_list != NULL) {
+					struct cil_list_item *item;
+					cil_list_for_each(item, param_list) {
+						param = item->data;
+						if (param->flavor == new->flavor) {
+							if (param->str == ((struct cil_symtab_datum*)new->data)->name) {
+								cil_tree_log(orig, CIL_ERR, "%s %s shadows a macro parameter", cil_node_to_string(new), ((struct cil_symtab_datum*)orig->data)->name);
+								cil_tree_log(namespace, CIL_ERR, "Note: macro declaration");
+								rc = SEPOL_ERR;
+								goto exit;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if (new->flavor == CIL_BLOCKINHERIT) {
+			blockinherit = new->data;
+			// if a blockinherit statement is copied before blockinherit are
+			// resolved (like in an in-statement), the block will not have been
+			// resolved yet, so there's nothing to append yet. This is fine,
+			// the copied blockinherit statement will be handled later, as if
+			// it wasn't in an in-statement
+			if (blockinherit->block != NULL) {
+				cil_list_append(blockinherit->block->bi_nodes, CIL_NODE, new);
+			}
+		}
+
+		if (parent->cl_head == NULL) {
+			parent->cl_head = new;
+			parent->cl_tail = new;
+		} else {
+			parent->cl_tail->next = new;
+			parent->cl_tail = new;
+		}
+
+		if (orig->cl_head != NULL) {
+			args->dest = new;
+		}
+	} else {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_node_destroy(&new);
+	return rc;
+}
+
+int __cil_copy_last_child_helper(__attribute__((unused)) struct cil_tree_node *orig, void *extra_args)
+{
+	struct cil_tree_node *node = NULL;
+	struct cil_args_copy *args = NULL;
+
+	args = extra_args;
+	node = args->dest;
+
+	if (node->flavor != CIL_ROOT) {
+		args->dest = node->parent;
+	}
+
+	return SEPOL_OK;
+}
+
+// dest is the parent node to copy into
+// if the copy is for a call to a macro, dest should be a pointer to the call
+int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_node *dest)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_copy extra_args;
+
+	extra_args.dest = dest;
+	extra_args.db = db;
+
+	rc = cil_tree_walk(orig, __cil_copy_node_helper, NULL,  __cil_copy_last_child_helper, &extra_args);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "cil_tree_walk failed, rc: %d\n", rc);
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
diff --git a/libsepol/cil/src/cil_copy_ast.h b/libsepol/cil/src/cil_copy_ast.h
new file mode 100644
index 0000000..78c34b8
--- /dev/null
+++ b/libsepol/cil/src/cil_copy_ast.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_COPY_H_
+#define CIL_COPY_H_
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+
+void cil_copy_list(struct cil_list *orig, struct cil_list **copy);
+int cil_copy_expr(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
+
+int cil_copy_block(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_blockabstract(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_blockinherit(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_perm(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_class(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classmapping(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_permset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+
+void cil_copy_classperms(struct cil_classperms *orig, struct cil_classperms **new);
+void cil_copy_classperms_set(struct cil_classperms_set *orig, struct cil_classperms_set **new);
+void cil_copy_classperms_list(struct cil_list *orig, struct cil_list **new);
+int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void *data, void **copy,  __attribute__((unused)) symtab_t *symtab);
+int cil_copy_common(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classcommon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sid(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sidorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_user(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userrole(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userbounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userprefix(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_role(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roletype(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_rolebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleallow(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_type(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typepermissive(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typeattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typealias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_nametypetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_rangetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_bool(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_avrule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_type_rule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sens(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sensalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_cat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_senscat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sensitivityorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_level(struct cil_db *db, struct cil_level *orig, struct cil_level **new);
+int cil_copy_level(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_levelrange(struct cil_db *db, struct cil_levelrange *orig, struct cil_levelrange *new);
+int cil_copy_levelrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_context(struct cil_db *db, struct cil_context *orig, struct cil_context *new);
+int cil_copy_context(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_filecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_portcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_ioportcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_fsuse(struct cil_db *db, void *data, void **copy, symtab_t *symtab); 
+int cil_copy_exrp(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
+int cil_copy_constrain(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_validatetrans(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_call(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_optional(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_ipaddr(struct cil_ipaddr *orig, struct cil_ipaddr *new);
+int cil_copy_ipaddr(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_boolif(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+
+int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_node *dest);
+
+#endif
diff --git a/libsepol/cil/src/cil_find.c b/libsepol/cil/src/cil_find.c
new file mode 100644
index 0000000..4134242
--- /dev/null
+++ b/libsepol/cil/src/cil_find.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/ebitmap.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_list.h"
+#include "cil_log.h"
+#include "cil_symtab.h"
+
+struct cil_args_find {
+	enum cil_flavor flavor;
+	void *target;
+	struct cil_list *matching;
+	int match_self;
+};
+
+static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
+{
+	enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
+	enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
+
+	if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+		struct cil_type *t1 = (struct cil_type *)d1;
+		struct cil_type *t2 = (struct cil_type *)d2;
+		if (t1->value == t2->value) {
+			return CIL_TRUE;
+		}
+	} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+		struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
+		struct cil_type *t = (struct cil_type *)d2;
+		if (ebitmap_get_bit(a->types, t->value)) {
+			return CIL_TRUE;
+		}
+	} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
+		struct cil_type *t = (struct cil_type *)d1;
+		struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
+		if (ebitmap_get_bit(a->types, t->value)) {
+			return CIL_TRUE;
+		}
+	} else {
+		/* Both are attributes */
+		struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
+		struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
+		if (d1 == d2) {
+			return CIL_TRUE;
+		} else if (ebitmap_match_any(a1->types, a2->types)) {
+			return CIL_TRUE;
+		}
+	}
+	return CIL_FALSE;
+}
+
+static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
+{
+	int rc = SEPOL_OK;
+	enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
+	enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
+
+	if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+		struct cil_type *t1 = (struct cil_type *)d1;
+		struct cil_type *t2 = (struct cil_type *)d2;
+		if (t1->value == t2->value) {
+			ebitmap_set_bit(matches, t1->value, 1);
+		}
+	} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+		struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
+		struct cil_type *t = (struct cil_type *)d2;
+		if (ebitmap_get_bit(a->types, t->value)) {
+			ebitmap_set_bit(matches, t->value, 1);
+		}
+	} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
+		struct cil_type *t = (struct cil_type *)d1;
+		struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
+		if (ebitmap_get_bit(a->types, t->value)) {
+			ebitmap_set_bit(matches, t->value, 1);
+		}
+	} else {
+		/* Both are attributes */
+		struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
+		struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
+		rc = ebitmap_and(matches, a1->types, a2->types);
+	}
+
+	return rc;
+}
+
+/* s1 is the src type that is matched with a self
+ * s2, and t2 are the source and type of the other rule
+ */
+static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2)
+{
+	int rc;
+	struct cil_tree_node *n1 = s1->nodes->head->data;
+	if (n1->flavor != CIL_TYPEATTRIBUTE) {
+		rc = cil_type_match_any(s1, t2);
+	} else {
+		struct cil_typeattribute *a = (struct cil_typeattribute *)s1;
+		ebitmap_t map;
+		ebitmap_init(&map);
+		rc = cil_type_matches(&map, s2, t2);
+		if (rc < 0) {
+			ebitmap_destroy(&map);
+			goto exit;
+		}
+		if (map.node == NULL) {
+			rc = CIL_FALSE;
+			goto exit;
+		}
+		rc = ebitmap_match_any(&map, a->types);
+		ebitmap_destroy(&map);
+	}
+
+exit:
+	return rc;
+}
+
+static int cil_classperms_match_any(struct cil_classperms *cp1, struct cil_classperms *cp2)
+{
+	struct cil_class *c1 = cp1->class;
+	struct cil_class *c2 = cp2->class;
+	struct cil_list_item *i1, *i2;
+
+	if (&c1->datum != &c2->datum) return CIL_FALSE;
+
+	cil_list_for_each(i1, cp1->perms) {
+		struct cil_perm *p1 = i1->data;
+		cil_list_for_each(i2, cp2->perms) {
+			struct cil_perm *p2 = i2->data;
+			if (&p1->datum == &p2->datum) return CIL_TRUE;
+		}
+	}
+	return CIL_FALSE;
+}
+
+static int __cil_classperms_list_match_any(struct cil_classperms *cp1, struct cil_list *cpl2)
+{
+	int rc;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, cpl2) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				rc = cil_classperms_match_any(cp1, cp);
+				if (rc == CIL_TRUE) return CIL_TRUE;
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					rc = __cil_classperms_list_match_any(cp1, cmp->classperms);
+					if (rc == CIL_TRUE) return CIL_TRUE;
+				}
+			}
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = __cil_classperms_list_match_any(cp1, cp->classperms);
+			if (rc == CIL_TRUE) return CIL_TRUE;
+		}
+	}
+	return CIL_FALSE;
+}
+
+static int cil_classperms_list_match_any(struct cil_list *cpl1, struct cil_list *cpl2)
+{
+	int rc;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, cpl1) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				rc = __cil_classperms_list_match_any(cp, cpl2);
+				if (rc == CIL_TRUE) return CIL_TRUE;
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					rc = cil_classperms_list_match_any(cmp->classperms, cpl2);
+					if (rc == CIL_TRUE) return CIL_TRUE;
+				}
+			}
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = cil_classperms_list_match_any(cp->classperms, cpl2);
+			if (rc == CIL_TRUE) return CIL_TRUE;
+		}
+	}
+	return CIL_FALSE;
+}
+
+static void __add_classes_from_classperms_list(struct cil_list *classperms, struct cil_list *class_list)
+{
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				cil_list_append(class_list, CIL_CLASS, cp->class);
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					__add_classes_from_classperms_list(cmp->classperms, class_list);
+				}
+			}
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			__add_classes_from_classperms_list(cp->classperms, class_list);
+		}
+	}
+}
+
+static int __add_classes_from_map_perms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct cil_list *class_list = args;
+	struct cil_perm *cmp = (struct cil_perm *)d;
+
+	__add_classes_from_classperms_list(cmp->classperms, class_list);
+
+	return SEPOL_OK;
+}
+
+struct cil_list *cil_expand_class(struct cil_class *class)
+{
+	struct cil_list *class_list;
+
+	cil_list_init(&class_list, CIL_CLASS);
+
+	if (FLAVOR(class) == CIL_CLASS) {
+		cil_list_append(class_list, CIL_CLASS, class);
+	} else { /* MAP */
+		cil_symtab_map(&class->perms, __add_classes_from_map_perms, class_list);
+	}
+
+	return class_list;
+}
+
+static int cil_permissionx_match_any(struct cil_permissionx *px1, struct cil_permissionx *px2)
+{
+	int rc = CIL_FALSE;
+	struct cil_list *cl1 = NULL;
+	struct cil_list *cl2 = NULL;
+
+	if (px1->kind != px2->kind) goto exit;
+
+	if (!ebitmap_match_any(px1->perms, px2->perms)) goto exit;
+
+	cl1 = cil_expand_class(px1->obj);
+	cl2 = cil_expand_class(px2->obj);
+
+	if (!cil_list_match_any(cl1, cl2)) goto exit;
+
+	rc = CIL_TRUE;
+
+exit:
+	cil_list_destroy(&cl1, CIL_FALSE);
+	cil_list_destroy(&cl2, CIL_FALSE);
+
+	return rc;
+}
+
+int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self)
+{
+	int rc = SEPOL_OK;
+	struct cil_symtab_datum *s1 = avrule->src;
+	struct cil_symtab_datum *t1 = avrule->tgt;
+	struct cil_symtab_datum *s2 = target->src;
+	struct cil_symtab_datum *t2 = target->tgt;
+
+	if (match_self != CIL_TRUE && avrule == target) goto exit;
+
+	if (avrule->rule_kind != target->rule_kind) goto exit;
+
+	if (avrule->is_extended != target->is_extended) goto exit;
+
+	if (!cil_type_match_any(s1, s2)) goto exit;
+
+	if (t1->fqn != CIL_KEY_SELF && t2->fqn != CIL_KEY_SELF) {
+		if (!cil_type_match_any(t1, t2)) goto exit;
+	} else {
+		if (t1->fqn == CIL_KEY_SELF && t2->fqn == CIL_KEY_SELF) {
+			/* The earlier check whether s1 and s2 matches is all that is needed */
+		} else if (t1->fqn == CIL_KEY_SELF) {
+			rc = cil_self_match_any(s1, s2, t2);
+			if (rc < 0) {
+				goto exit;
+			} else if (rc == CIL_FALSE) {
+				rc = SEPOL_OK;
+				goto exit;
+			}
+		} else if (t2->fqn == CIL_KEY_SELF) {
+			rc = cil_self_match_any(s2, s1, t1);
+			if (rc < 0) {
+				goto exit;
+			} else if (rc == CIL_FALSE) {
+				rc = SEPOL_OK;
+				goto exit;
+			}
+		}
+	}
+
+	if (!target->is_extended) {
+		if (cil_classperms_list_match_any(avrule->perms.classperms, target->perms.classperms)) {
+			cil_list_append(matching, CIL_NODE, node);
+		}
+	} else {
+		if (cil_permissionx_match_any(avrule->perms.x.permx, target->perms.x.permx)) {
+			cil_list_append(matching, CIL_NODE, node);
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_find_matching_avrule_in_ast(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_OK;
+	struct cil_args_find *args = extra_args;
+
+	if (node->flavor == CIL_BLOCK) {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+			goto exit;
+		}
+	} else if (node->flavor == CIL_MACRO) {
+		*finished = CIL_TREE_SKIP_HEAD;
+		goto exit;
+	} else if (node->flavor == CIL_AVRULE || node->flavor == CIL_AVRULEX) {
+		if (node->flavor == args->flavor) {
+			rc = cil_find_matching_avrule(node, node->data, args->target, args->matching, args->match_self);
+		}
+	}
+
+exit:
+	return rc;
+}
+
+int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self)
+{
+	int rc;
+	struct cil_args_find args;
+
+	args.flavor = flavor;
+	args.target = target;
+	args.matching = matching;
+	args.match_self = match_self;
+
+	rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args);
+	if (rc) {
+		cil_log(CIL_ERR, "An error occurred while searching for avrule in AST\n");
+	}
+
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_find.h b/libsepol/cil/src/cil_find.h
new file mode 100644
index 0000000..463ef34
--- /dev/null
+++ b/libsepol/cil/src/cil_find.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+#ifndef CIL_FIND_H_
+#define CIL_FIND_H_
+
+int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self);
+struct cil_list *cil_expand_class(struct cil_class *class);
+
+#endif
diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
new file mode 100644
index 0000000..cd08b97
--- /dev/null
+++ b/libsepol/cil/src/cil_flavor.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2013 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_FLAVOR_H_
+#define CIL_FLAVOR_H_
+
+/*
+	Tree/list node types
+*/
+#define CIL_MIN_OP_OPERANDS 1000
+#define CIL_MIN_DECLARATIVE 2000
+
+enum cil_flavor {
+	CIL_NONE = 0,
+	CIL_ROOT,
+	CIL_NODE,
+	CIL_STRING,
+	CIL_DATUM,
+	CIL_LIST,
+	CIL_LIST_ITEM,
+	CIL_PARAM,
+	CIL_ARGS,
+	CIL_BLOCKINHERIT,
+	CIL_BLOCKABSTRACT,
+	CIL_IN,
+	CIL_CALL,
+	CIL_BOOLEANIF,
+	CIL_TUNABLEIF,
+	CIL_CONDBLOCK,
+	CIL_CONDTRUE,
+	CIL_CONDFALSE,
+	CIL_CLASSORDER,
+	CIL_CLASSCOMMON,
+	CIL_CLASSMAPPING,
+	CIL_CLASSPERMS,
+	CIL_CLASSPERMS_SET,
+	CIL_CLASSPERMISSIONSET,
+	CIL_USERPREFIX,
+	CIL_USERROLE,
+	CIL_USERATTRIBUTESET,
+	CIL_USERLEVEL,
+	CIL_USERRANGE,
+	CIL_USERBOUNDS,
+	CIL_SELINUXUSER,
+	CIL_SELINUXUSERDEFAULT,
+	CIL_ROLEATTRIBUTESET,
+	CIL_ROLETYPE,
+	CIL_ROLEBOUNDS,
+	CIL_TYPEATTRIBUTESET,
+	CIL_TYPEALIASACTUAL,
+	CIL_TYPEBOUNDS,
+	CIL_TYPEPERMISSIVE,
+	CIL_SENSALIASACTUAL,
+	CIL_SENSITIVITYORDER,
+	CIL_SENSCAT,
+	CIL_CATALIASACTUAL,
+	CIL_CATORDER,
+	CIL_SIDORDER,
+	CIL_ROLEALLOW,
+	CIL_AVRULE,
+	CIL_AVRULEX,
+	CIL_ROLETRANSITION,
+	CIL_TYPE_RULE,
+	CIL_NAMETYPETRANSITION,
+	CIL_RANGETRANSITION,
+	CIL_CONSTRAIN,
+	CIL_MLSCONSTRAIN,
+	CIL_VALIDATETRANS,
+	CIL_MLSVALIDATETRANS,
+	CIL_SIDCONTEXT,
+	CIL_FSUSE,
+	CIL_FILECON,
+	CIL_PORTCON,
+	CIL_NODECON,
+	CIL_GENFSCON,
+	CIL_NETIFCON,
+	CIL_PIRQCON,
+	CIL_IOMEMCON,
+	CIL_IOPORTCON,
+	CIL_PCIDEVICECON,
+	CIL_DEVICETREECON,
+	CIL_DEFAULTUSER,
+	CIL_DEFAULTROLE,
+	CIL_DEFAULTTYPE,
+	CIL_DEFAULTRANGE,
+	CIL_HANDLEUNKNOWN,
+	CIL_MLS,
+	CIL_SRC_INFO,
+
+/*
+ *          boolean  constraint  set  catset
+ *  dom                  X
+ *  domby                X
+ *  incomp               X
+ *  eq         X         X
+ *  ne         X         X
+ *  and        X         X        X    X
+ *  not        X         X        X    X
+ *  or         X         X        X    X
+ *  xor        X                  X    X
+ *  all                           X    X
+ *  range                              X
+*/
+	CIL_OP = CIL_MIN_OP_OPERANDS,
+	CIL_ALL,
+	CIL_AND,
+	CIL_OR,
+	CIL_XOR,
+	CIL_NOT,
+	CIL_EQ,
+	CIL_NEQ,
+	CIL_RANGE,
+	CIL_CONS_DOM,
+	CIL_CONS_DOMBY,
+	CIL_CONS_INCOMP,
+	CIL_CONS_OPERAND,
+	CIL_CONS_U1,
+	CIL_CONS_U2,
+	CIL_CONS_U3,
+	CIL_CONS_T1,
+	CIL_CONS_T2,
+	CIL_CONS_T3,
+	CIL_CONS_R1,
+	CIL_CONS_R2,
+	CIL_CONS_R3,
+	CIL_CONS_L1,
+	CIL_CONS_L2,
+	CIL_CONS_H1,
+	CIL_CONS_H2,
+
+	CIL_BLOCK = CIL_MIN_DECLARATIVE,
+	CIL_MACRO,
+	CIL_OPTIONAL,
+	CIL_BOOL,
+	CIL_TUNABLE,
+	CIL_PERM,
+	CIL_MAP_PERM,
+	CIL_COMMON,
+	CIL_CLASS,
+	CIL_MAP_CLASS,
+	CIL_CLASSPERMISSION,
+	CIL_USER,
+	CIL_USERATTRIBUTE,
+	CIL_ROLE,
+	CIL_ROLEATTRIBUTE,
+	CIL_TYPE,
+	CIL_TYPEATTRIBUTE,
+	CIL_TYPEALIAS,
+	CIL_SENS,
+	CIL_SENSALIAS,
+	CIL_CAT,
+	CIL_CATSET,
+	CIL_CATALIAS,
+	CIL_LEVEL,
+	CIL_LEVELRANGE,
+	CIL_SID,
+	CIL_NAME,
+	CIL_CONTEXT,
+	CIL_IPADDR,
+	CIL_POLICYCAP,
+	CIL_PERMISSIONX
+};
+
+
+#endif /* CIL_FLAVOR_H_ */
diff --git a/libsepol/cil/src/cil_fqn.c b/libsepol/cil/src/cil_fqn.c
new file mode 100644
index 0000000..dad1347
--- /dev/null
+++ b/libsepol/cil/src/cil_fqn.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_strpool.h"
+#include "cil_symtab.h"
+
+struct cil_fqn_args {
+	char prefix[CIL_MAX_NAME_LENGTH];
+	int len;
+	struct cil_tree_node *node;
+};
+
+static int __cil_fqn_qualify_decls(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct cil_fqn_args *fqn_args = args;
+	struct cil_symtab_datum *datum = (struct cil_symtab_datum *)d;
+	int newlen;
+	char prefix[CIL_MAX_NAME_LENGTH];
+	int rc = SEPOL_OK;
+
+	if (fqn_args->len == 0) {
+		goto exit;
+	}
+
+	newlen = fqn_args->len + strlen(datum->name);
+	if (newlen >= CIL_MAX_NAME_LENGTH) {
+		cil_log(CIL_INFO, "Fully qualified name for %s is too long\n", datum->name);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+	strcpy(prefix, fqn_args->prefix);
+	strcat(prefix, datum->name);
+	datum->fqn = cil_strpool_add(prefix);
+
+exit:
+	return rc;
+}
+
+static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct cil_fqn_args *fqn_args = args;
+	struct cil_fqn_args child_args;
+	struct cil_block *block = (struct cil_block *)d;
+	struct cil_symtab_datum *datum = (struct cil_symtab_datum *)block;
+	struct cil_tree_node *node = NODE(datum);
+	int i;
+	int rc = SEPOL_OK;
+
+	if (node->flavor != CIL_BLOCK) {
+		goto exit;
+	}
+
+	int newlen = fqn_args->len + strlen(datum->name) + 1;
+	if (newlen >= CIL_MAX_NAME_LENGTH) {
+		cil_log(CIL_INFO, "Fully qualified name for block %s is too long\n", datum->name);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	child_args.node = node;
+	child_args.len = newlen;
+	strcpy(child_args.prefix, fqn_args->prefix);
+	strcat(child_args.prefix, datum->name);
+	strcat(child_args.prefix, ".");
+
+	for (i=1; i<CIL_SYM_NUM; i++) {
+		switch (i) {
+		case CIL_SYM_CLASSPERMSETS:
+		case CIL_SYM_CONTEXTS:
+		case CIL_SYM_LEVELRANGES:
+		case CIL_SYM_IPADDRS:
+		case CIL_SYM_NAMES:
+		case CIL_SYM_PERMX:
+			/* These do not show up in the kernal policy */
+			break;
+		case CIL_SYM_POLICYCAPS:
+			/* Valid policy capability names are defined in libsepol */
+			break;
+		default:
+			rc = cil_symtab_map(&(block->symtab[i]), __cil_fqn_qualify_decls, &child_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			break;
+		}
+	}
+
+	rc = cil_symtab_map(&(block->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &child_args);
+
+exit:
+	if (rc != SEPOL_OK) {
+		cil_tree_log(child_args.node, CIL_ERR,"Problem qualifying names in block");
+	}
+
+	return rc;
+}
+
+int cil_fqn_qualify(struct cil_tree_node *root_node)
+{
+	struct cil_root *root = root_node->data;
+	struct cil_fqn_args fqn_args;
+
+	fqn_args.prefix[0] = '\0';
+	fqn_args.len = 0;
+	fqn_args.node = root_node;
+
+	return cil_symtab_map(&(root->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &fqn_args);
+}
+
diff --git a/libsepol/cil/src/cil_fqn.h b/libsepol/cil/src/cil_fqn.h
new file mode 100644
index 0000000..9248ca1
--- /dev/null
+++ b/libsepol/cil/src/cil_fqn.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_FQN_H_
+#define CIL_FQN_H_
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+
+int cil_fqn_qualify(struct cil_tree_node *root_node);
+
+#endif /* CIL_FQN_H_ */
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
new file mode 100644
index 0000000..5875dc9
--- /dev/null
+++ b/libsepol/cil/src/cil_internal.h
@@ -0,0 +1,1034 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_INTERNAL_H_
+#define CIL_INTERNAL_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/policydb.h>
+
+#include <cil/cil.h>
+
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+#include "cil_mem.h"
+
+#define CIL_MAX_NAME_LENGTH 2048
+
+
+enum cil_pass {
+	CIL_PASS_INIT = 0,
+
+	CIL_PASS_TIF,
+	CIL_PASS_IN,
+	CIL_PASS_BLKIN_LINK,
+	CIL_PASS_BLKIN_COPY,
+	CIL_PASS_BLKABS,
+	CIL_PASS_MACRO,
+	CIL_PASS_CALL1,
+	CIL_PASS_CALL2,
+	CIL_PASS_ALIAS1,
+	CIL_PASS_ALIAS2,
+	CIL_PASS_MISC1,
+	CIL_PASS_MLS,
+	CIL_PASS_MISC2,
+	CIL_PASS_MISC3,
+
+	CIL_PASS_NUM
+};
+
+
+/*
+	Keywords
+*/
+char *CIL_KEY_CONS_T1;
+char *CIL_KEY_CONS_T2;
+char *CIL_KEY_CONS_T3;
+char *CIL_KEY_CONS_R1;
+char *CIL_KEY_CONS_R2;
+char *CIL_KEY_CONS_R3;
+char *CIL_KEY_CONS_U1;
+char *CIL_KEY_CONS_U2;
+char *CIL_KEY_CONS_U3;
+char *CIL_KEY_CONS_L1;
+char *CIL_KEY_CONS_L2;
+char *CIL_KEY_CONS_H1;
+char *CIL_KEY_CONS_H2;
+char *CIL_KEY_AND;
+char *CIL_KEY_OR;
+char *CIL_KEY_NOT;
+char *CIL_KEY_EQ;
+char *CIL_KEY_NEQ;
+char *CIL_KEY_CONS_DOM;
+char *CIL_KEY_CONS_DOMBY;
+char *CIL_KEY_CONS_INCOMP;
+char *CIL_KEY_CONDTRUE;
+char *CIL_KEY_CONDFALSE;
+char *CIL_KEY_SELF;
+char *CIL_KEY_OBJECT_R;
+char *CIL_KEY_STAR;
+char *CIL_KEY_TCP;
+char *CIL_KEY_UDP;
+char *CIL_KEY_DCCP;
+char *CIL_KEY_AUDITALLOW;
+char *CIL_KEY_TUNABLEIF;
+char *CIL_KEY_ALLOW;
+char *CIL_KEY_DONTAUDIT;
+char *CIL_KEY_TYPETRANSITION;
+char *CIL_KEY_TYPECHANGE;
+char *CIL_KEY_CALL;
+char *CIL_KEY_TUNABLE;
+char *CIL_KEY_XOR;
+char *CIL_KEY_ALL;
+char *CIL_KEY_RANGE;
+char *CIL_KEY_GLOB;
+char *CIL_KEY_FILE;
+char *CIL_KEY_DIR;
+char *CIL_KEY_CHAR;
+char *CIL_KEY_BLOCK;
+char *CIL_KEY_SOCKET;
+char *CIL_KEY_PIPE;
+char *CIL_KEY_SYMLINK;
+char *CIL_KEY_ANY;
+char *CIL_KEY_XATTR;
+char *CIL_KEY_TASK;
+char *CIL_KEY_TRANS;
+char *CIL_KEY_TYPE;
+char *CIL_KEY_ROLE;
+char *CIL_KEY_USER;
+char *CIL_KEY_USERATTRIBUTE;
+char *CIL_KEY_USERATTRIBUTESET;
+char *CIL_KEY_SENSITIVITY;
+char *CIL_KEY_CATEGORY;
+char *CIL_KEY_CATSET;
+char *CIL_KEY_LEVEL;
+char *CIL_KEY_LEVELRANGE;
+char *CIL_KEY_CLASS;
+char *CIL_KEY_IPADDR;
+char *CIL_KEY_MAP_CLASS;
+char *CIL_KEY_CLASSPERMISSION;
+char *CIL_KEY_BOOL;
+char *CIL_KEY_STRING;
+char *CIL_KEY_NAME;
+char *CIL_KEY_SOURCE;
+char *CIL_KEY_TARGET;
+char *CIL_KEY_LOW;
+char *CIL_KEY_HIGH;
+char *CIL_KEY_LOW_HIGH;
+char *CIL_KEY_HANDLEUNKNOWN;
+char *CIL_KEY_HANDLEUNKNOWN_ALLOW;
+char *CIL_KEY_HANDLEUNKNOWN_DENY;
+char *CIL_KEY_HANDLEUNKNOWN_REJECT;
+char *CIL_KEY_MACRO;
+char *CIL_KEY_IN;
+char *CIL_KEY_MLS;
+char *CIL_KEY_DEFAULTRANGE;
+char *CIL_KEY_BLOCKINHERIT;
+char *CIL_KEY_BLOCKABSTRACT;
+char *CIL_KEY_CLASSORDER;
+char *CIL_KEY_CLASSMAPPING;
+char *CIL_KEY_CLASSPERMISSIONSET;
+char *CIL_KEY_COMMON;
+char *CIL_KEY_CLASSCOMMON;
+char *CIL_KEY_SID;
+char *CIL_KEY_SIDCONTEXT;
+char *CIL_KEY_SIDORDER;
+char *CIL_KEY_USERLEVEL;
+char *CIL_KEY_USERRANGE;
+char *CIL_KEY_USERBOUNDS;
+char *CIL_KEY_USERPREFIX;
+char *CIL_KEY_SELINUXUSER;
+char *CIL_KEY_SELINUXUSERDEFAULT;
+char *CIL_KEY_TYPEATTRIBUTE;
+char *CIL_KEY_TYPEATTRIBUTESET;
+char *CIL_KEY_TYPEALIAS;
+char *CIL_KEY_TYPEALIASACTUAL;
+char *CIL_KEY_TYPEBOUNDS;
+char *CIL_KEY_TYPEPERMISSIVE;
+char *CIL_KEY_RANGETRANSITION;
+char *CIL_KEY_USERROLE;
+char *CIL_KEY_ROLETYPE;
+char *CIL_KEY_ROLETRANSITION;
+char *CIL_KEY_ROLEALLOW;
+char *CIL_KEY_ROLEATTRIBUTE;
+char *CIL_KEY_ROLEATTRIBUTESET;
+char *CIL_KEY_ROLEBOUNDS;
+char *CIL_KEY_BOOLEANIF;
+char *CIL_KEY_NEVERALLOW;
+char *CIL_KEY_TYPEMEMBER;
+char *CIL_KEY_SENSALIAS;
+char *CIL_KEY_SENSALIASACTUAL;
+char *CIL_KEY_CATALIAS;
+char *CIL_KEY_CATALIASACTUAL;
+char *CIL_KEY_CATORDER;
+char *CIL_KEY_SENSITIVITYORDER;
+char *CIL_KEY_SENSCAT;
+char *CIL_KEY_CONSTRAIN;
+char *CIL_KEY_MLSCONSTRAIN;
+char *CIL_KEY_VALIDATETRANS;
+char *CIL_KEY_MLSVALIDATETRANS;
+char *CIL_KEY_CONTEXT;
+char *CIL_KEY_FILECON;
+char *CIL_KEY_PORTCON;
+char *CIL_KEY_NODECON;
+char *CIL_KEY_GENFSCON;
+char *CIL_KEY_NETIFCON;
+char *CIL_KEY_PIRQCON;
+char *CIL_KEY_IOMEMCON;
+char *CIL_KEY_IOPORTCON;
+char *CIL_KEY_PCIDEVICECON;
+char *CIL_KEY_DEVICETREECON;
+char *CIL_KEY_FSUSE;
+char *CIL_KEY_POLICYCAP;
+char *CIL_KEY_OPTIONAL;
+char *CIL_KEY_DEFAULTUSER;
+char *CIL_KEY_DEFAULTROLE;
+char *CIL_KEY_DEFAULTTYPE;
+char *CIL_KEY_ROOT;
+char *CIL_KEY_NODE;
+char *CIL_KEY_PERM;
+char *CIL_KEY_ALLOWX;
+char *CIL_KEY_AUDITALLOWX;
+char *CIL_KEY_DONTAUDITX;
+char *CIL_KEY_NEVERALLOWX;
+char *CIL_KEY_PERMISSIONX;
+char *CIL_KEY_IOCTL;
+char *CIL_KEY_UNORDERED;
+char *CIL_KEY_SRC_INFO;
+char *CIL_KEY_SRC_CIL;
+char *CIL_KEY_SRC_HLL;
+
+/*
+	Symbol Table Array Indices
+*/
+enum cil_sym_index {
+	CIL_SYM_BLOCKS = 0,
+	CIL_SYM_USERS,
+	CIL_SYM_ROLES,
+	CIL_SYM_TYPES,
+	CIL_SYM_COMMONS,
+	CIL_SYM_CLASSES,
+	CIL_SYM_CLASSPERMSETS,
+	CIL_SYM_BOOLS,
+	CIL_SYM_TUNABLES,
+	CIL_SYM_SENS,
+	CIL_SYM_CATS,
+	CIL_SYM_SIDS,
+	CIL_SYM_CONTEXTS,
+	CIL_SYM_LEVELS,
+	CIL_SYM_LEVELRANGES,
+	CIL_SYM_POLICYCAPS,
+	CIL_SYM_IPADDRS,
+	CIL_SYM_NAMES,
+	CIL_SYM_PERMX,
+	CIL_SYM_NUM,
+	CIL_SYM_UNKNOWN,
+	CIL_SYM_PERMS	// Special case for permissions. This symtab is not included in arrays
+};
+
+enum cil_sym_array {
+	CIL_SYM_ARRAY_ROOT = 0,
+	CIL_SYM_ARRAY_BLOCK,
+	CIL_SYM_ARRAY_IN,
+	CIL_SYM_ARRAY_MACRO,
+	CIL_SYM_ARRAY_CONDBLOCK,
+	CIL_SYM_ARRAY_NUM
+};
+
+extern int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM];
+
+#define CIL_CLASS_SYM_SIZE	256
+
+struct cil_db {
+	struct cil_tree *parse;
+	struct cil_tree *ast;
+	struct cil_type *selftype;
+	struct cil_list *sidorder;
+	struct cil_list *classorder;
+	struct cil_list *catorder;
+	struct cil_list *sensitivityorder;
+	struct cil_sort *netifcon;
+	struct cil_sort *genfscon;
+	struct cil_sort *filecon;
+	struct cil_sort *nodecon;
+	struct cil_sort *portcon;
+	struct cil_sort *pirqcon;
+	struct cil_sort *iomemcon;
+	struct cil_sort *ioportcon;
+	struct cil_sort *pcidevicecon;
+	struct cil_sort *devicetreecon;
+	struct cil_sort *fsuse;
+	struct cil_list *userprefixes;
+	struct cil_list *selinuxusers;
+	struct cil_list *names;
+	int num_types_and_attrs;
+	int num_classes;
+	int num_cats;
+	int num_types;
+	int num_roles;
+	int num_users;
+	struct cil_type **val_to_type;
+	struct cil_role **val_to_role;
+	struct cil_user **val_to_user;
+	int disable_dontaudit;
+	int disable_neverallow;
+	int preserve_tunables;
+	int handle_unknown;
+	int mls;
+	int target_platform;
+	int policy_version;
+};
+
+struct cil_root {
+	symtab_t symtab[CIL_SYM_NUM];
+};
+
+struct cil_sort {
+	enum cil_flavor flavor;
+	uint32_t count;
+	uint32_t index;
+	void **array;
+};
+
+struct cil_block {
+	struct cil_symtab_datum datum;
+	symtab_t symtab[CIL_SYM_NUM];
+	uint16_t is_abstract;
+	struct cil_list *bi_nodes;
+};
+
+struct cil_blockinherit {
+	char *block_str;
+	struct cil_block *block;
+};
+
+struct cil_blockabstract {
+	char *block_str;
+};
+
+struct cil_in {
+	symtab_t symtab[CIL_SYM_NUM];
+	char *block_str;
+};
+
+struct cil_optional {
+	struct cil_symtab_datum datum;
+	int enabled;
+};
+
+struct cil_perm {
+	struct cil_symtab_datum datum;
+	unsigned int value;
+	struct cil_list *classperms; /* Only used for map perms */
+};
+
+struct cil_class {
+	struct cil_symtab_datum datum;
+	symtab_t perms;
+	unsigned int num_perms;
+	struct cil_class *common; /* Only used for kernel class */
+	uint32_t ordered; /* Only used for kernel class */
+};
+
+struct cil_classorder {
+	struct cil_list *class_list_str;
+};
+
+struct cil_classperms_set {
+	char *set_str;
+	struct cil_classpermission *set;
+};
+
+struct cil_classperms {
+	char *class_str;
+	struct cil_class *class;
+	struct cil_list *perm_strs;
+	struct cil_list *perms;
+};
+
+struct cil_classpermission {
+	struct cil_symtab_datum datum;
+	struct cil_list *classperms;
+};
+
+struct cil_classpermissionset {
+	char *set_str;
+	struct cil_list *classperms;
+};
+
+struct cil_classmapping {
+	char *map_class_str;
+	char *map_perm_str;
+	struct cil_list *classperms;
+};
+
+struct cil_classcommon {
+	char *class_str;
+	char *common_str;
+};
+
+struct cil_alias {
+	struct cil_symtab_datum datum;
+	void *actual;
+};
+
+struct cil_aliasactual {
+	char *alias_str;
+	char *actual_str;
+};
+
+struct cil_sid {
+	struct cil_symtab_datum datum;
+	struct cil_context *context;
+	uint32_t ordered;
+};
+
+struct cil_sidcontext {
+	char *sid_str;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_sidorder {
+	struct cil_list *sid_list_str;
+};
+
+struct cil_user {
+	struct cil_symtab_datum datum;
+	struct cil_user *bounds;
+	ebitmap_t *roles;
+	struct cil_level *dftlevel;
+	struct cil_levelrange *range;
+	int value;
+};
+
+struct cil_userattribute {
+	struct cil_symtab_datum datum;
+	struct cil_list *expr_list;
+	ebitmap_t *users;
+};
+
+struct cil_userattributeset {
+	char *attr_str;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_userrole {
+	char *user_str;
+	void *user;
+	char *role_str;
+	void *role;
+};
+
+struct cil_userlevel {
+	char *user_str;
+	char *level_str;
+	struct cil_level *level;
+};
+
+struct cil_userrange {
+	char *user_str;
+	char *range_str;
+	struct cil_levelrange *range;
+};
+
+struct cil_userprefix {
+	char *user_str;
+	struct cil_user *user;
+	char *prefix_str;
+};
+
+struct cil_selinuxuser {
+	char *name_str;
+	char *user_str;
+	struct cil_user *user;
+	char *range_str;
+	struct cil_levelrange *range;
+};
+
+struct cil_role {
+	struct cil_symtab_datum datum;
+	struct cil_role *bounds;
+	ebitmap_t *types;
+	int value;
+};
+
+struct cil_roleattribute {
+	struct cil_symtab_datum datum;
+	struct cil_list *expr_list;
+	ebitmap_t *roles;
+};
+
+struct cil_roleattributeset {
+	char *attr_str;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_roletype {
+	char *role_str;
+	void *role; /* role or attribute */
+	char *type_str;
+	void *type; /* type, alias, or attribute */
+};
+
+struct cil_type	{
+	struct cil_symtab_datum datum;
+	struct cil_type *bounds;
+	int value;
+};
+
+struct cil_typeattribute {
+	struct cil_symtab_datum datum;
+	struct cil_list *expr_list;
+	ebitmap_t *types;
+	int used;	// whether or not this typeattribute was used and should be added to the binary
+};
+
+struct cil_typeattributeset {
+	char *attr_str;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_typepermissive {
+	char *type_str;
+	void *type; /* type or alias */
+};
+
+struct cil_name {
+	struct cil_symtab_datum datum;
+	char *name_str;
+};
+
+struct cil_nametypetransition {
+	char *src_str;
+	void *src; /* type, alias, or attribute */
+	char *tgt_str;
+	void *tgt; /* type, alias, or attribute */
+	char *obj_str;
+	struct cil_class *obj;
+	char *name_str;
+	struct cil_name *name;
+	char *result_str;
+	void *result; /* type or alias */
+
+};
+
+struct cil_rangetransition {
+	char *src_str;
+	void *src; /* type, alias, or attribute */
+	char *exec_str;
+	void *exec; /* type, alias, or attribute */
+	char *obj_str;
+	struct cil_class *obj;
+	char *range_str;
+	struct cil_levelrange *range;
+};
+
+struct cil_bool {
+	struct cil_symtab_datum datum;
+	uint16_t value;
+};
+
+struct cil_tunable {
+	struct cil_symtab_datum datum;
+	uint16_t value;
+};
+
+#define CIL_AVRULE_ALLOWED     1
+#define CIL_AVRULE_AUDITALLOW  2
+#define CIL_AVRULE_DONTAUDIT   8
+#define CIL_AVRULE_NEVERALLOW 128
+#define CIL_AVRULE_AV         (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+struct cil_avrule {
+	int is_extended;
+	uint32_t rule_kind;
+	char *src_str;
+	void *src; /* type, alias, or attribute */
+	char *tgt_str;	
+	void *tgt; /* type, alias, or attribute */
+	union {
+		struct cil_list *classperms;
+		struct {
+			char *permx_str;
+			struct cil_permissionx *permx;
+		} x;
+	} perms;
+};
+
+#define CIL_PERMX_KIND_IOCTL 1
+struct cil_permissionx {
+	struct cil_symtab_datum datum;
+	uint32_t kind;
+	char *obj_str;
+	struct cil_class *obj;
+	struct cil_list *expr_str;
+	ebitmap_t *perms;
+};
+
+#define CIL_TYPE_TRANSITION 16
+#define CIL_TYPE_MEMBER     32
+#define CIL_TYPE_CHANGE     64
+#define CIL_AVRULE_TYPE       (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+struct cil_type_rule {
+	uint32_t rule_kind;
+	char *src_str;
+	void *src; /* type, alias, or attribute */
+	char *tgt_str;
+	void *tgt; /* type, alias, or attribute */
+	char *obj_str;
+	struct cil_class *obj;
+	char *result_str;
+	void *result; /* type or alias */
+};
+
+struct cil_roletransition {
+	char *src_str;
+	struct cil_role *src;
+	char *tgt_str;	
+	void *tgt; /* type, alias, or attribute */
+	char *obj_str;
+	struct cil_class *obj;
+	char *result_str;
+	struct cil_role *result;
+};
+
+struct cil_roleallow {
+	char *src_str;
+	void *src; /* role or attribute */
+	char *tgt_str;
+	void *tgt; /* role or attribute */
+};
+
+struct cil_sens {
+	struct cil_symtab_datum datum;
+	struct cil_list *cats_list;
+	uint32_t ordered;
+};
+
+struct cil_sensorder {
+	struct cil_list *sens_list_str;
+};
+
+struct cil_cat {
+	struct cil_symtab_datum datum;
+	uint32_t ordered;
+	int value;
+};
+
+struct cil_cats {
+	uint32_t evaluated;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_catset {
+	struct cil_symtab_datum datum;
+	struct cil_cats *cats;
+};
+
+struct cil_catorder {
+	struct cil_list *cat_list_str;
+};
+
+struct cil_senscat {
+	char *sens_str;
+	struct cil_cats *cats;
+};
+
+struct cil_level {
+	struct cil_symtab_datum datum;
+	char *sens_str;
+	struct cil_sens *sens;
+	struct cil_cats *cats;
+};
+
+struct cil_levelrange {
+	struct cil_symtab_datum datum;
+	char *low_str;
+	struct cil_level *low;
+	char *high_str;
+	struct cil_level *high;
+};
+
+struct cil_context {
+	struct cil_symtab_datum datum;
+	char *user_str;
+	struct cil_user *user;
+	char *role_str;
+	struct cil_role *role;
+	char *type_str;
+	void *type; /* type or alias */
+	char *range_str;
+	struct cil_levelrange *range;
+};
+
+enum cil_filecon_types {
+	CIL_FILECON_FILE = 1,
+	CIL_FILECON_DIR,
+	CIL_FILECON_CHAR,
+	CIL_FILECON_BLOCK,
+	CIL_FILECON_SOCKET,
+	CIL_FILECON_PIPE,
+	CIL_FILECON_SYMLINK,
+	CIL_FILECON_ANY
+};
+
+struct cil_filecon {
+	char *path_str;
+	enum cil_filecon_types type;
+	char *context_str;
+	struct cil_context *context;
+};
+
+enum cil_protocol {
+	CIL_PROTOCOL_UDP = 1,
+	CIL_PROTOCOL_TCP,
+	CIL_PROTOCOL_DCCP
+};
+
+struct cil_portcon {
+	enum cil_protocol proto;
+	uint32_t port_low;
+	uint32_t port_high;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_nodecon {
+	char *addr_str;
+	struct cil_ipaddr *addr;
+	char *mask_str;
+	struct cil_ipaddr *mask;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_ipaddr {
+	struct cil_symtab_datum datum;
+	int family;
+	union {
+		struct in_addr v4;
+		struct in6_addr v6;
+	} ip;
+};
+
+struct cil_genfscon {
+	char *fs_str;
+	char *path_str;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_netifcon {
+	char *interface_str;
+	char *if_context_str;
+	struct cil_context *if_context;
+	char *packet_context_str;
+	struct cil_context *packet_context;
+	char *context_str;
+};
+
+struct cil_pirqcon {
+	uint32_t pirq;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_iomemcon {
+	uint64_t iomem_low;
+	uint64_t iomem_high;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_ioportcon {
+	uint32_t ioport_low;
+	uint32_t ioport_high;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_pcidevicecon {
+	uint32_t dev;
+	char *context_str;
+	struct cil_context *context;
+};
+
+struct cil_devicetreecon {
+	char *path;
+	char *context_str;
+	struct cil_context *context;
+};
+
+
+/* Ensure that CIL uses the same values as sepol services.h */
+enum cil_fsuse_types {
+	CIL_FSUSE_XATTR = SECURITY_FS_USE_XATTR,
+	CIL_FSUSE_TASK = SECURITY_FS_USE_TASK,
+	CIL_FSUSE_TRANS = SECURITY_FS_USE_TRANS
+};
+
+struct cil_fsuse {
+	enum cil_fsuse_types type;
+	char *fs_str;
+	char *context_str;
+	struct cil_context *context;
+};
+
+#define CIL_MLS_LEVELS "l1 l2 h1 h2" 
+#define CIL_CONSTRAIN_KEYS "t1 t2 r1 r2 u1 u2"
+#define CIL_MLSCONSTRAIN_KEYS CIL_MLS_LEVELS CIL_CONSTRAIN_KEYS
+#define CIL_CONSTRAIN_OPER "== != eq dom domby incomp not and or"
+struct cil_constrain {
+	struct cil_list *classperms;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_validatetrans {
+	char *class_str;
+	struct cil_class *class;
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_param {
+	char *str;
+	enum cil_flavor flavor;
+};
+
+struct cil_macro {
+	struct cil_symtab_datum datum;
+	symtab_t symtab[CIL_SYM_NUM];
+	struct cil_list *params;
+};
+
+struct cil_args {
+	char *arg_str;
+	struct cil_symtab_datum *arg;
+	char *param_str;
+	enum cil_flavor flavor;
+};
+
+struct cil_call {
+	char *macro_str;
+	struct cil_macro *macro;
+	struct cil_tree *args_tree;
+	struct cil_list *args;
+	int copied;
+};
+
+#define CIL_TRUE	1
+#define CIL_FALSE	0
+
+struct cil_condblock {
+	enum cil_flavor flavor;
+	symtab_t symtab[CIL_SYM_NUM];
+};
+
+struct cil_booleanif {
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+	int preserved_tunable;
+};
+
+struct cil_tunableif {
+	struct cil_list *str_expr;
+	struct cil_list *datum_expr;
+};
+
+struct cil_policycap {
+	struct cil_symtab_datum datum;
+};
+
+struct cil_bounds {
+	char *parent_str;
+	char *child_str;
+};
+
+/* Ensure that CIL uses the same values as sepol policydb.h */
+enum cil_default_object {
+	CIL_DEFAULT_SOURCE = DEFAULT_SOURCE,
+	CIL_DEFAULT_TARGET = DEFAULT_TARGET,
+};
+
+/* Default labeling behavior for users, roles, and types */
+struct cil_default {
+	enum cil_flavor flavor;
+	struct cil_list *class_strs;
+	struct cil_list *class_datums;
+	enum cil_default_object object;
+};
+
+/* Ensure that CIL uses the same values as sepol policydb.h */
+enum cil_default_object_range {
+	CIL_DEFAULT_SOURCE_LOW      = DEFAULT_SOURCE_LOW,
+	CIL_DEFAULT_SOURCE_HIGH     = DEFAULT_SOURCE_HIGH,
+	CIL_DEFAULT_SOURCE_LOW_HIGH = DEFAULT_SOURCE_LOW_HIGH,
+	CIL_DEFAULT_TARGET_LOW      = DEFAULT_TARGET_LOW,
+	CIL_DEFAULT_TARGET_HIGH     = DEFAULT_TARGET_HIGH,
+	CIL_DEFAULT_TARGET_LOW_HIGH = DEFAULT_TARGET_LOW_HIGH,
+};
+
+/* Default labeling behavior for range */
+struct cil_defaultrange {
+	struct cil_list *class_strs;
+	struct cil_list *class_datums;
+	enum cil_default_object_range object_range;
+};
+
+struct cil_handleunknown {
+	int handle_unknown;
+};
+
+struct cil_mls {
+	int value;
+};
+
+struct cil_src_info {
+	int is_cil;
+	char *path;
+};
+
+void cil_db_init(struct cil_db **db);
+void cil_db_destroy(struct cil_db **db);
+
+void cil_root_init(struct cil_root **root);
+void cil_root_destroy(struct cil_root *root);
+
+void cil_destroy_data(void **data, enum cil_flavor flavor);
+
+int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *index);
+const char * cil_node_to_string(struct cil_tree_node *node);
+
+int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size);
+int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size);
+int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size);
+
+void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM]);
+void cil_symtab_array_destroy(symtab_t symtab[]);
+void cil_destroy_ast_symtabs(struct cil_tree_node *root);
+int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index);
+
+void cil_sort_init(struct cil_sort **sort);
+void cil_sort_destroy(struct cil_sort **sort);
+void cil_netifcon_init(struct cil_netifcon **netifcon);
+void cil_context_init(struct cil_context **context);
+void cil_level_init(struct cil_level **level);
+void cil_levelrange_init(struct cil_levelrange **lvlrange);
+void cil_sens_init(struct cil_sens **sens);
+void cil_block_init(struct cil_block **block);
+void cil_blockinherit_init(struct cil_blockinherit **inherit);
+void cil_blockabstract_init(struct cil_blockabstract **abstract);
+void cil_in_init(struct cil_in **in);
+void cil_class_init(struct cil_class **class);
+void cil_classorder_init(struct cil_classorder **classorder);
+void cil_classcommon_init(struct cil_classcommon **classcommon);
+void cil_sid_init(struct cil_sid **sid);
+void cil_sidcontext_init(struct cil_sidcontext **sidcontext);
+void cil_sidorder_init(struct cil_sidorder **sidorder);
+void cil_userrole_init(struct cil_userrole **userrole);
+void cil_userprefix_init(struct cil_userprefix **userprefix);
+void cil_selinuxuser_init(struct cil_selinuxuser **selinuxuser);
+void cil_roleattribute_init(struct cil_roleattribute **attribute);
+void cil_roleattributeset_init(struct cil_roleattributeset **attrset);
+void cil_roletype_init(struct cil_roletype **roletype);
+void cil_typeattribute_init(struct cil_typeattribute **attribute);
+void cil_typeattributeset_init(struct cil_typeattributeset **attrset);
+void cil_alias_init(struct cil_alias **alias);
+void cil_aliasactual_init(struct cil_aliasactual **aliasactual);
+void cil_typepermissive_init(struct cil_typepermissive **typeperm);
+void cil_name_init(struct cil_name **name);
+void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans);
+void cil_rangetransition_init(struct cil_rangetransition **rangetrans);
+void cil_bool_init(struct cil_bool **cilbool);
+void cil_boolif_init(struct cil_booleanif **bif);
+void cil_condblock_init(struct cil_condblock **cb);
+void cil_tunable_init(struct cil_tunable **ciltun);
+void cil_tunif_init(struct cil_tunableif **tif);
+void cil_avrule_init(struct cil_avrule **avrule);
+void cil_permissionx_init(struct cil_permissionx **permx);
+void cil_type_rule_init(struct cil_type_rule **type_rule);
+void cil_roletransition_init(struct cil_roletransition **roletrans);
+void cil_roleallow_init(struct cil_roleallow **role_allow);
+void cil_catset_init(struct cil_catset **catset);
+void cil_cats_init(struct cil_cats **cats);
+void cil_senscat_init(struct cil_senscat **senscat);
+void cil_filecon_init(struct cil_filecon **filecon);
+void cil_portcon_init(struct cil_portcon **portcon);
+void cil_nodecon_init(struct cil_nodecon **nodecon);
+void cil_genfscon_init(struct cil_genfscon **genfscon);
+void cil_pirqcon_init(struct cil_pirqcon **pirqcon);
+void cil_iomemcon_init(struct cil_iomemcon **iomemcon);
+void cil_ioportcon_init(struct cil_ioportcon **ioportcon);
+void cil_pcidevicecon_init(struct cil_pcidevicecon **pcidevicecon);
+void cil_devicetreecon_init(struct cil_devicetreecon **devicetreecon);
+void cil_fsuse_init(struct cil_fsuse **fsuse);
+void cil_constrain_init(struct cil_constrain **constrain);
+void cil_validatetrans_init(struct cil_validatetrans **validtrans);
+void cil_ipaddr_init(struct cil_ipaddr **ipaddr);
+void cil_perm_init(struct cil_perm **perm);
+void cil_classpermission_init(struct cil_classpermission **cp);
+void cil_classpermissionset_init(struct cil_classpermissionset **cps);
+void cil_classperms_set_init(struct cil_classperms_set **cp_set);
+void cil_classperms_init(struct cil_classperms **cp);
+void cil_classmapping_init(struct cil_classmapping **mapping);
+void cil_user_init(struct cil_user **user);
+void cil_userlevel_init(struct cil_userlevel **usrlvl);
+void cil_userrange_init(struct cil_userrange **userrange);
+void cil_role_init(struct cil_role **role);
+void cil_type_init(struct cil_type **type);
+void cil_cat_init(struct cil_cat **cat);
+void cil_catorder_init(struct cil_catorder **catorder);
+void cil_sensorder_init(struct cil_sensorder **sensorder);
+void cil_args_init(struct cil_args **args);
+void cil_call_init(struct cil_call **call);
+void cil_optional_init(struct cil_optional **optional);
+void cil_param_init(struct cil_param **param);
+void cil_macro_init(struct cil_macro **macro);
+void cil_policycap_init(struct cil_policycap **policycap);
+void cil_bounds_init(struct cil_bounds **bounds);
+void cil_default_init(struct cil_default **def);
+void cil_defaultrange_init(struct cil_defaultrange **def);
+void cil_handleunknown_init(struct cil_handleunknown **unk);
+void cil_mls_init(struct cil_mls **mls);
+void cil_src_info_init(struct cil_src_info **info);
+void cil_userattribute_init(struct cil_userattribute **attribute);
+void cil_userattributeset_init(struct cil_userattributeset **attrset);
+
+#endif
diff --git a/libsepol/cil/src/cil_lexer.h b/libsepol/cil/src/cil_lexer.h
new file mode 100644
index 0000000..ab555d8
--- /dev/null
+++ b/libsepol/cil/src/cil_lexer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_LEXER_H_
+#define CIL_LEXER_H_
+
+#include <stdint.h>
+
+#define OPAREN 1
+#define CPAREN 2
+#define SYMBOL 3
+#define QSTRING 4
+#define COMMENT 5
+#define HLL_LINEMARK 6
+#define NEWLINE 7
+#define END_OF_FILE 8
+#define UNKNOWN 9
+
+struct token {
+	uint32_t type;
+	char * value;
+	uint32_t line;
+};
+
+int cil_lexer_setup(char *buffer, uint32_t size);
+void cil_lexer_destroy(void);
+int cil_lexer_next(struct token *tok);
+
+#endif /* CIL_LEXER_H_ */
diff --git a/libsepol/cil/src/cil_lexer.l b/libsepol/cil/src/cil_lexer.l
new file mode 100644
index 0000000..e28c33e
--- /dev/null
+++ b/libsepol/cil/src/cil_lexer.l
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+%{
+	#include <stdint.h>
+	#include <sepol/errcodes.h>
+	#include "cil_internal.h"
+	#include "cil_lexer.h"
+	#include "cil_log.h"
+	#include "cil_mem.h"
+	char *value =  NULL;
+	int line = 1;
+%}
+
+%option nounput
+%option noinput
+%option noyywrap
+%option prefix="cil_yy"
+
+digit		[0-9]
+alpha		[a-zA-Z]
+spec_char	[\[\]\.\@\=\/\*\-\_\$\%\+\-\!\|\&\^\:\~\`\#\{\}\'\<\>\?\,]
+symbol		({digit}|{alpha}|{spec_char})+
+white		[ \t]
+newline		[\n\r]
+qstring		\"[^"\n]*\"
+hll_lm          ^;;\*
+comment		;
+
+%%
+{newline}	line++; return NEWLINE;
+{hll_lm}	value=yytext; return HLL_LINEMARK;
+{comment}	value=yytext; return COMMENT;
+"("		value=yytext; return OPAREN;
+")"		value=yytext; return CPAREN;
+{symbol}	value=yytext; return SYMBOL;
+{white}		;
+{qstring}	value=yytext; return QSTRING;
+<<EOF>>		return END_OF_FILE;
+.		value=yytext; return UNKNOWN;
+%%
+
+int cil_lexer_setup(char *buffer, uint32_t size)
+{
+	size = (yy_size_t)size;
+	if (yy_scan_buffer(buffer, size) == NULL) {
+		cil_log(CIL_INFO, "Lexer failed to setup buffer\n");
+		return SEPOL_ERR;
+	}
+
+	line = 1;
+
+	return SEPOL_OK;
+}
+
+void cil_lexer_destroy(void)
+{
+	yylex_destroy();
+}
+
+int cil_lexer_next(struct token *tok)
+{
+	tok->type = yylex();
+	tok->value = value;
+	tok->line = line;
+
+	return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_list.c b/libsepol/cil/src/cil_list.c
new file mode 100644
index 0000000..4e7843c
--- /dev/null
+++ b/libsepol/cil/src/cil_list.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_list_error(const char* msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	cil_vlog(CIL_ERR, msg, ap);
+	va_end(ap);
+	exit(1);
+}
+
+void cil_list_init(struct cil_list **list, enum cil_flavor flavor)
+{
+	struct cil_list *new_list = cil_malloc(sizeof(*new_list));
+	new_list->head = NULL;
+	new_list->tail = NULL;
+	new_list->flavor = flavor;
+	*list = new_list;
+}
+
+void cil_list_destroy(struct cil_list **list, unsigned destroy_data)
+{
+	if (*list == NULL) {
+		return;
+	}
+
+	struct cil_list_item *item = (*list)->head;
+	struct cil_list_item *next = NULL;
+	while (item != NULL)
+	{
+		next = item->next;
+		if (item->flavor == CIL_LIST) {
+			cil_list_destroy((struct cil_list**)&(item->data), destroy_data);
+			free(item);
+		} else {
+			cil_list_item_destroy(&item, destroy_data);
+		}
+		item = next;
+	}
+	free(*list);
+	*list = NULL;
+}
+
+void cil_list_item_init(struct cil_list_item **item)
+{
+	struct cil_list_item *new_item = cil_malloc(sizeof(*new_item));
+	new_item->next = NULL;
+	new_item->flavor = CIL_NONE;
+	new_item->data = NULL;
+
+	*item = new_item;
+}
+
+void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data)
+{
+	if (destroy_data) {
+		cil_destroy_data(&(*item)->data, (*item)->flavor);
+	}
+	free(*item);
+	*item = NULL;
+}
+
+void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data)
+{
+	struct cil_list_item *item;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to append data to a NULL list");
+	}
+
+	cil_list_item_init(&item);
+	item->flavor = flavor;
+	item->data = data;
+
+	if (list->tail == NULL) {
+		list->head = item;
+		list->tail = item;
+		return;
+	}
+
+	list->tail->next = item;
+	list->tail = item;
+}
+
+void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data)
+{
+	struct cil_list_item *item;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to prepend data to a NULL list");
+	}
+
+	cil_list_item_init(&item);
+	item->flavor = flavor;
+	item->data = data;
+
+	if (list->tail == NULL) {
+		list->head = item;
+		list->tail = item;
+		return;
+	}
+
+	item->next = list->head;
+	list->head = item;
+}
+
+struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data)
+{
+	struct cil_list_item *item;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to append data to a NULL list");
+	}
+
+	if (curr == NULL) {
+		/* Insert at the front of the list */
+		cil_list_prepend(list, flavor, data);
+		return list->head;
+	}
+
+	if (curr == list->tail) {
+		cil_list_append(list, flavor, data);
+		return list->tail;
+	}
+
+	cil_list_item_init(&item);
+	item->flavor = flavor;
+	item->data = data;
+	item->next = curr->next;
+
+	curr->next = item;
+
+	return item;
+}
+
+void cil_list_append_item(struct cil_list *list, struct cil_list_item *item)
+{
+	struct cil_list_item *last = item;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to append an item to a NULL list");
+	}
+
+	if (item == NULL) {
+		cil_list_error("Attempt to append a NULL item to a list");
+	}
+
+	while (last->next != NULL) {
+		last = last->next;
+	}
+
+	if (list->tail == NULL) {
+		list->head = item;
+		list->tail = last;
+		return;
+	}
+
+	list->tail->next = item;
+	list->tail = last;
+
+}
+
+void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item)
+{
+	struct cil_list_item *last = item;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to prepend an item to a NULL list");
+	}
+
+	if (item == NULL) {
+		cil_list_error("Attempt to prepend a NULL item to a list");
+	}
+
+	while (last->next != NULL) {
+		last = last->next;
+	}
+
+	if (list->tail == NULL) {
+		list->head = item;
+		list->tail = last;
+		return;
+	}
+
+	last->next = list->head;
+	list->head = item;
+}
+
+void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data)
+{
+	struct cil_list_item *item;
+	struct cil_list_item *previous = NULL;
+
+	if (list == NULL) {
+		cil_list_error("Attempt to remove data from a NULL list");
+	}
+
+	cil_list_for_each(item, list) {
+		if (item->data == data && item->flavor == flavor) {
+			if (previous == NULL) {
+				list->head = item->next;
+			} else {
+				previous->next = item->next;
+			}
+			if (item->next == NULL) {
+				list->tail = previous;
+			}
+			cil_list_item_destroy(&item, destroy_data);
+			break;
+		}
+		previous = item;
+	}
+}
+
+int cil_list_contains(struct cil_list *list, void *data)
+{
+	struct cil_list_item *curr = NULL;
+
+	cil_list_for_each(curr, list) {
+		if (curr->data == data) {
+			return CIL_TRUE;
+		}
+	}
+
+	return CIL_FALSE;
+}
+
+int cil_list_match_any(struct cil_list *l1, struct cil_list *l2)
+{
+	struct cil_list_item *i1;
+	struct cil_list_item *i2;
+
+	cil_list_for_each(i1, l1) {
+		cil_list_for_each(i2, l2) {
+			if (i1->data == i2->data && i1->flavor == i2->flavor) {
+				return CIL_TRUE;
+			}
+		}
+	}
+
+	return CIL_FALSE;
+}
diff --git a/libsepol/cil/src/cil_list.h b/libsepol/cil/src/cil_list.h
new file mode 100644
index 0000000..6b4708a
--- /dev/null
+++ b/libsepol/cil/src/cil_list.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_LIST_H_
+#define CIL_LIST_H_
+
+#include "cil_flavor.h"
+
+struct cil_list {
+	struct cil_list_item *head;
+	struct cil_list_item *tail;
+	enum cil_flavor flavor;
+};
+
+struct cil_list_item {
+	struct cil_list_item *next;
+	enum cil_flavor flavor;
+	void *data;
+};
+
+#define cil_list_for_each(item, list) \
+	for (item = (list)->head; item != NULL; item = item->next)
+
+
+void cil_list_init(struct cil_list **list, enum cil_flavor flavor);
+void cil_list_destroy (struct cil_list **list, unsigned destroy_data);
+void cil_list_item_init(struct cil_list_item **item);
+void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data);
+void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data);
+void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data);
+void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data);
+struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data);
+void cil_list_append_item(struct cil_list *list, struct cil_list_item *item);
+void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item);
+int cil_list_contains(struct cil_list *list, void *data);
+int cil_list_match_any(struct cil_list *l1, struct cil_list *l2);
+
+#endif
diff --git a/libsepol/cil/src/cil_log.c b/libsepol/cil/src/cil_log.c
new file mode 100644
index 0000000..b222b15
--- /dev/null
+++ b/libsepol/cil/src/cil_log.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <cil/cil.h>
+#include "cil_log.h"
+
+static enum cil_log_level cil_log_level = CIL_ERR;
+
+void cil_default_log_handler(__attribute__((unused)) int lvl, char *msg)
+{
+	fprintf(stderr, "%s", msg);
+}
+
+void (*cil_log_handler)(int lvl, char *msg) = &cil_default_log_handler;
+
+void cil_set_log_handler(void (*handler)(int lvl, char *msg))
+{
+	cil_log_handler = handler;
+}
+
+__attribute__ ((format (printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args)
+{
+	if (cil_log_level >= lvl) {
+		char buff[MAX_LOG_SIZE];
+		vsnprintf(buff, MAX_LOG_SIZE, msg, args);
+		(*cil_log_handler)(cil_log_level, buff);
+	}
+}
+
+__attribute__ ((format (printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...)
+{
+    va_list args;
+    va_start(args, msg);
+    cil_vlog(lvl, msg, args);
+    va_end(args);
+}
+
+void cil_set_log_level(enum cil_log_level lvl)
+{
+	cil_log_level = lvl;
+}
diff --git a/libsepol/cil/src/cil_log.h b/libsepol/cil/src/cil_log.h
new file mode 100644
index 0000000..4112aaf
--- /dev/null
+++ b/libsepol/cil/src/cil_log.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+#ifndef CIL_LOG_H_
+#define CIL_LOG_H_
+
+#include <stdlib.h>
+#include <cil/cil.h>
+
+#define MAX_LOG_SIZE 512
+
+__attribute__ ((format(printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args);
+__attribute__ ((format(printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...);
+
+#endif // CIL_LOG_H_
diff --git a/libsepol/cil/src/cil_mem.c b/libsepol/cil/src/cil_mem.c
new file mode 100644
index 0000000..12c59be
--- /dev/null
+++ b/libsepol/cil/src/cil_mem.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "cil_log.h"
+
+__attribute__((noreturn)) void cil_default_mem_error_handler(void)
+{
+	cil_log(CIL_ERR, "Failed to allocate memory\n");
+	exit(1);
+}
+
+void (*cil_mem_error_handler)(void) = &cil_default_mem_error_handler;
+
+void cil_set_mem_error_handler(void (*handler)(void))
+{
+	cil_mem_error_handler = handler;
+}
+
+void *cil_malloc(size_t size)
+{
+	void *mem = malloc(size);
+	if (mem == NULL){
+		if (size == 0) {
+			return NULL;
+		}
+		(*cil_mem_error_handler)();
+	}
+
+	return mem;
+}
+
+void *cil_calloc(size_t num_elements, size_t element_size)
+{
+	void *mem = calloc(num_elements, element_size);
+	if (mem == NULL){
+		(*cil_mem_error_handler)();
+	}
+
+	return mem;
+}
+
+void *cil_realloc(void *ptr, size_t size)
+{
+	void *mem = realloc(ptr, size);
+	if (mem == NULL){
+		if (size == 0) {
+			return NULL;
+		}
+		(*cil_mem_error_handler)();
+	}
+
+	return mem;
+}
+
+
+char *cil_strdup(const char *str)
+{
+	char *mem = NULL;
+
+	if (str == NULL) {
+		return NULL;
+	}
+
+	mem = strdup(str);
+	if (mem == NULL) {
+		(*cil_mem_error_handler)();
+	}
+
+	return mem;
+}
+
+__attribute__ ((format (printf, 2, 3))) int cil_asprintf(char **strp, const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	va_start(ap, fmt);
+	rc = vasprintf(strp, fmt, ap);
+	va_end(ap);
+
+	if (rc == -1) {
+		(*cil_mem_error_handler)();
+	}
+
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_mem.h b/libsepol/cil/src/cil_mem.h
new file mode 100644
index 0000000..902ce13
--- /dev/null
+++ b/libsepol/cil/src/cil_mem.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_MEM_H_
+#define CIL_MEM_H_
+
+/* Wrapped malloc that catches errors and calls the error callback */
+void *cil_malloc(size_t size);
+void *cil_calloc(size_t num_elements, size_t element_size);
+void *cil_realloc(void *ptr, size_t size);
+char *cil_strdup(const char *str);
+int cil_asprintf(char **strp, const char *fmt, ...);
+void (*cil_mem_error_handler)(void);
+
+#endif /* CIL_MEM_H_ */
+
diff --git a/libsepol/cil/src/cil_parser.c b/libsepol/cil/src/cil_parser.c
new file mode 100644
index 0000000..101520c
--- /dev/null
+++ b/libsepol/cil/src/cil_parser.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_lexer.h"
+#include "cil_strpool.h"
+#include "cil_stack.h"
+
+char *CIL_KEY_HLL_LMS;
+char *CIL_KEY_HLL_LMX;
+char *CIL_KEY_HLL_LME;
+
+struct hll_info {
+	int hll_lineno;
+	int hll_expand;
+};
+
+static void push_hll_info(struct cil_stack *stack, int hll_lineno, int hll_expand)
+{
+	struct hll_info *new = cil_malloc(sizeof(*new));
+
+	new->hll_lineno = hll_lineno;
+	new->hll_expand = hll_expand;
+
+	cil_stack_push(stack, CIL_NONE, new);
+}
+
+static void pop_hll_info(struct cil_stack *stack, int *hll_lineno, int *hll_expand)
+{
+	struct cil_stack_item *curr = cil_stack_pop(stack);
+	struct cil_stack_item *prev = cil_stack_peek(stack);
+	struct hll_info *old;
+
+	free(curr->data);
+
+	if (!prev) {
+		*hll_lineno = -1;
+		*hll_expand = -1;
+	} else {
+		old = prev->data;
+		*hll_lineno = old->hll_lineno;
+		*hll_expand = old->hll_expand;
+	}
+}
+
+static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, int line, int hll_line, void *value)
+{
+	cil_tree_node_init(node);
+	(*node)->parent = current;
+	(*node)->flavor = CIL_NODE;
+	(*node)->line = line;
+	(*node)->hll_line = hll_line;
+	(*node)->data = value;
+}
+
+static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current)
+{
+	if (current->cl_head == NULL) {
+		current->cl_head = node;
+	} else {
+		current->cl_tail->next = node;
+	}
+	current->cl_tail = node;
+}
+
+static int add_hll_linemark(struct cil_tree_node **current, int *hll_lineno, int *hll_expand, struct cil_stack *stack, char *path)
+{
+	char *hll_type;
+	struct cil_tree_node *node;
+	struct token tok;
+	char *hll_file;
+	char *end = NULL;
+
+	cil_lexer_next(&tok);
+	hll_type = cil_strpool_add(tok.value);
+	if (hll_type == CIL_KEY_HLL_LME) {
+		if (cil_stack_is_empty(stack)) {
+			cil_log(CIL_ERR, "Line mark end without start\n");
+			goto exit;
+		}
+		pop_hll_info(stack, hll_lineno, hll_expand);
+		*current = (*current)->parent;
+	} else {
+		create_node(&node, *current, tok.line, *hll_lineno, NULL);
+		insert_node(node, *current);
+		*current = node;
+
+		create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_INFO);
+		insert_node(node, *current);
+
+		create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_HLL);
+		insert_node(node, *current);
+
+		if (hll_type == CIL_KEY_HLL_LMS) {
+			*hll_expand = 0;
+		} else if (hll_type == CIL_KEY_HLL_LMX) {
+			*hll_expand = 1;
+		} else {
+			cil_log(CIL_ERR, "Invalid line mark syntax\n");
+			goto exit;
+		}
+
+		cil_lexer_next(&tok);
+		if (tok.type != SYMBOL) {
+			cil_log(CIL_ERR, "Invalid line mark syntax\n");
+			goto exit;
+		}
+		*hll_lineno = strtol(tok.value, &end, 10);
+		if (errno == ERANGE || *end != '\0') {
+			cil_log(CIL_ERR, "Problem parsing line number for line mark\n");
+			goto exit;
+		}
+
+		push_hll_info(stack, *hll_lineno, *hll_expand);
+
+		cil_lexer_next(&tok);
+		if (tok.type != SYMBOL && tok.type != QSTRING) {
+			cil_log(CIL_ERR, "Invalid line mark syntax\n");
+			goto exit;
+		}
+
+		if (tok.type == QSTRING) {
+			tok.value[strlen(tok.value) - 1] = '\0';
+			tok.value = tok.value+1;
+		}
+
+		hll_file = cil_strpool_add(tok.value);
+
+		create_node(&node, *current, tok.line, *hll_lineno, hll_file);
+		insert_node(node, *current);
+	}
+
+	cil_lexer_next(&tok);
+	if (tok.type != NEWLINE) {
+		cil_log(CIL_ERR, "Invalid line mark syntax\n");
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Problem with high-level line mark at line %d of %s\n", tok.line, path);
+	return SEPOL_ERR;
+}
+
+static void add_cil_path(struct cil_tree_node **current, char *path)
+{
+	struct cil_tree_node *node;
+
+	create_node(&node, *current, 0, 0, NULL);
+	insert_node(node, *current);
+	*current = node;
+
+	create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO);
+	insert_node(node, *current);
+
+	create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL);
+	insert_node(node, *current);
+
+	create_node(&node, *current, 0, 0, path);
+	insert_node(node, *current);
+}
+
+int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree)
+{
+
+	int paren_count = 0;
+
+	struct cil_tree *tree = NULL;
+	struct cil_tree_node *node = NULL;
+	struct cil_tree_node *current = NULL;
+	char *path = cil_strpool_add(_path);
+	struct cil_stack *stack;
+	int hll_lineno = -1;
+	int hll_expand = -1;
+	struct token tok;
+	int rc = SEPOL_OK;
+
+	CIL_KEY_HLL_LMS = cil_strpool_add("lms");
+	CIL_KEY_HLL_LMX = cil_strpool_add("lmx");
+	CIL_KEY_HLL_LME = cil_strpool_add("lme");
+
+	cil_stack_init(&stack);
+
+	cil_lexer_setup(buffer, size);
+
+	tree = *parse_tree;
+	current = tree->root;
+
+	add_cil_path(&current, path);
+
+	do {
+		cil_lexer_next(&tok);
+		switch (tok.type) {
+		case HLL_LINEMARK:
+			rc = add_hll_linemark(&current, &hll_lineno, &hll_expand, stack, path);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			break;
+		case OPAREN:
+			paren_count++;
+
+			create_node(&node, current, tok.line, hll_lineno, NULL);
+			insert_node(node, current);
+			current = node;
+			break;
+		case CPAREN:
+			paren_count--;
+			if (paren_count < 0) {
+				cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path);
+				goto exit;
+			}
+			current = current->parent;
+			break;
+		case QSTRING:
+			tok.value[strlen(tok.value) - 1] = '\0';
+			tok.value = tok.value+1;
+		case SYMBOL:
+			if (paren_count == 0) {
+				cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path);
+				goto exit;
+			}
+
+			create_node(&node, current, tok.line, hll_lineno, cil_strpool_add(tok.value));
+			insert_node(node, current);
+			break;
+		case NEWLINE :
+			if (!hll_expand) {
+				hll_lineno++;
+			}
+			break;
+		case COMMENT:
+			while (tok.type != NEWLINE && tok.type != END_OF_FILE) {
+				cil_lexer_next(&tok);
+			}
+			if (!hll_expand) {
+				hll_lineno++;
+			}
+			if (tok.type != END_OF_FILE) {
+				break;
+			}
+			// Fall through if EOF
+		case END_OF_FILE:
+			if (paren_count > 0) {
+				cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path);
+				goto exit;
+			}
+			if (!cil_stack_is_empty(stack)) {
+				cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path);
+				goto exit;
+			}
+			break;
+		case UNKNOWN:
+			cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path);
+			goto exit;
+		default:
+			cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path);
+			goto exit;
+		}
+	}
+	while (tok.type != END_OF_FILE);
+
+	cil_lexer_destroy();
+
+	cil_stack_destroy(&stack);
+
+	*parse_tree = tree;
+
+	return SEPOL_OK;
+
+exit:
+	while (!cil_stack_is_empty(stack)) {
+		pop_hll_info(stack, &hll_lineno, &hll_expand);
+	}
+	cil_stack_destroy(&stack);
+
+	return SEPOL_ERR;
+}
diff --git a/libsepol/cil/src/cil_parser.h b/libsepol/cil/src/cil_parser.h
new file mode 100644
index 0000000..02ecb78
--- /dev/null
+++ b/libsepol/cil/src/cil_parser.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_PARSER_H_
+#define CIL_PARSER_H_
+
+#include "cil_tree.h"
+
+int cil_parser(char *path, char *buffer, uint32_t size, struct cil_tree **parse_tree);
+
+#endif /* CIL_PARSER_H_ */
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
new file mode 100644
index 0000000..382129b
--- /dev/null
+++ b/libsepol/cil/src/cil_policy.c
@@ -0,0 +1,1426 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sepol/policydb/conditional.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_policy.h"
+#include "cil_symtab.h"
+#include "cil_strpool.h"
+
+#define SEPOL_DONE			555
+
+#define CLASS_DECL			0
+#define ISIDS				1
+#define COMMONS				2
+#define CLASSES				3
+#define INTERFACES			4
+#define SENS				5
+#define CATS				6
+#define LEVELS				7
+#define CONSTRAINS			8
+#define TYPEATTRTYPES			9
+#define ALIASES				10
+#define ALLOWS				11
+#define CONDS				12
+#define USERROLES			13
+#define SIDS				14
+#define NETIFCONS			15 
+
+#define BUFFER				1024
+#define NUM_POLICY_FILES		16
+
+struct cil_args_genpolicy {
+	struct cil_list *users;
+	struct cil_list *sens;
+	struct cil_list *cats;
+	FILE **file_arr;
+};
+
+struct cil_args_booleanif {
+	FILE **file_arr;
+	uint32_t *file_index;
+};
+
+
+int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
+
+int cil_combine_policy(FILE **file_arr, FILE *policy_file)
+{
+	char temp[BUFFER];
+	int i, rc, rc_read, rc_write;
+
+	for(i=0; i<NUM_POLICY_FILES; i++) {
+		fseek(file_arr[i], 0, SEEK_SET);
+		while (!feof(file_arr[i])) {
+			rc_read = fread(temp, 1, BUFFER, file_arr[i]);
+			if (rc_read == 0 && ferror(file_arr[i])) {
+				cil_log(CIL_ERR, "Error reading temp policy file\n");
+				return SEPOL_ERR;
+			}
+			rc_write = 0;
+			while (rc_read > rc_write) {
+				rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file);
+				rc_write += rc;
+				if (rc == 0 && ferror(file_arr[i])) {
+					cil_log(CIL_ERR, "Error writing to policy.conf\n");
+					return SEPOL_ERR;
+				}
+			}
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i=0; i<sort->count; i++) {
+		struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "portcon ");
+		if (portcon->proto == CIL_PROTOCOL_UDP) {
+			fprintf(file_arr[NETIFCONS], "udp ");
+		} else if (portcon->proto == CIL_PROTOCOL_TCP) {
+			fprintf(file_arr[NETIFCONS], "tcp ");
+		} else if (portcon->proto == CIL_PROTOCOL_DCCP) {
+			fprintf(file_arr[NETIFCONS], "dccp ");
+		}
+		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low);
+		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high);
+		cil_context_to_policy(file_arr, NETIFCONS, portcon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i=0; i<sort->count; i++) {
+		struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str);
+		fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str);
+		cil_context_to_policy(file_arr, NETIFCONS, genfscon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i=0; i<sort->count; i++) {
+		struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str);
+		cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context);
+		fprintf(file_arr[NETIFCONS], " ");
+		cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+	int rc = SEPOL_ERR;
+
+	for (i=0; i<sort->count; i++) {
+		struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i];
+		char *buf = NULL;
+		errno = 0;
+		if (nodecon->addr->family == AF_INET) {
+			buf = cil_malloc(INET_ADDRSTRLEN);
+			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN);
+		} else if (nodecon->addr->family == AF_INET6) {
+			buf = cil_malloc(INET6_ADDRSTRLEN);
+			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN);
+		}
+
+		if (errno != 0) {
+			cil_log(CIL_INFO, "Failed to convert ip address to string\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		fprintf(file_arr[NETIFCONS], "nodecon %s ", buf);
+		free(buf);
+
+		if (nodecon->mask->family == AF_INET) {
+			buf = cil_malloc(INET_ADDRSTRLEN);
+			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN);
+		} else if (nodecon->mask->family == AF_INET6) {
+			buf = cil_malloc(INET6_ADDRSTRLEN);
+			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN);
+		}
+
+		if (errno != 0) {
+			cil_log(CIL_INFO, "Failed to convert mask to string\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		fprintf(file_arr[NETIFCONS], "%s ", buf);
+		free(buf);
+
+		cil_context_to_policy(file_arr, NETIFCONS, nodecon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < sort->count; i++) {
+		struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq);
+		cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < sort->count; i++) {
+		struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high);
+		cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < sort->count; i++) {
+		struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
+		cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < sort->count; i++) {
+		struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i];
+		fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev);
+		cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+	uint32_t i = 0;
+
+	for (i=0; i<sort->count; i++) {
+		struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i];
+		if (fsuse->type == CIL_FSUSE_XATTR) {
+			fprintf(file_arr[NETIFCONS], "fs_use_xattr ");
+		} else if (fsuse->type == CIL_FSUSE_TASK) {
+			fprintf(file_arr[NETIFCONS], "fs_use_task ");
+		} else if (fsuse->type == CIL_FSUSE_TRANS) {
+			fprintf(file_arr[NETIFCONS], "fs_use_trans ");
+		} else {
+			return SEPOL_ERR;
+		}
+		fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str);
+		cil_context_to_policy(file_arr, NETIFCONS, fsuse->context);
+		fprintf(file_arr[NETIFCONS], ";\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor)
+{
+	struct cil_list_item *curr_key;
+	struct cil_multimap_item *new_data;
+
+	if (list == NULL || key == NULL) {
+		return SEPOL_ERR;
+	}
+
+	cil_list_for_each(curr_key, list) {
+		struct cil_multimap_item *curr_multimap_item = curr_key->data;
+		if (curr_multimap_item != NULL) {
+			if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) {
+				struct cil_list_item *curr_value;
+				cil_list_for_each(curr_value, curr_multimap_item->values) {
+					if (curr_value == (struct cil_list_item*)value) {
+						return SEPOL_OK;;
+					}
+				}
+				cil_list_append(curr_multimap_item->values, val_flavor, value);
+			}
+		} else {
+			cil_log(CIL_INFO, "No data in list item\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	new_data = cil_malloc(sizeof(*new_data));
+	new_data->key = key;
+	cil_list_init(&new_data->values, CIL_LIST_ITEM);
+	if (value != NULL) {
+		cil_list_append(new_data->values, val_flavor, value);
+	}
+	cil_list_append(list, key_flavor, new_data);
+
+	return SEPOL_OK;
+}
+
+int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles)
+{
+	struct cil_list_item *current_user;
+
+	if (userroles == NULL) {
+		return SEPOL_OK;
+	}
+	
+	cil_list_for_each(current_user, userroles) {
+		struct cil_multimap_item *user_multimap_item = current_user->data;
+		struct cil_list_item *current_role;
+		if (user_multimap_item->values->head == NULL) {
+			cil_log(CIL_INFO, "No roles associated with user %s\n",  
+					user_multimap_item->key->name);
+			return SEPOL_ERR;
+		}
+
+		fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name);
+
+		cil_list_for_each(current_role, user_multimap_item->values) {
+			fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name);
+		}
+		fprintf(file_arr[USERROLES], " };\n"); 
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats)
+{
+	struct cil_list_item *curr_cat;
+
+	if (cats == NULL) {
+		return SEPOL_OK;
+	}
+
+	cil_list_for_each(curr_cat, cats) {
+		struct cil_multimap_item *cat_multimap_item = curr_cat->data;
+		fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name);
+		if (cat_multimap_item->values->head == NULL) {
+			fprintf(file_arr[CATS], ";\n");
+		} else {
+			struct cil_list_item *curr_catalias;
+			fprintf(file_arr[CATS], " alias");
+			cil_list_for_each(curr_catalias, cat_multimap_item->values) {
+				fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name);
+			}
+			fprintf(file_arr[CATS], ";\n"); 
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens)
+{
+	struct cil_list_item *curr_sens;
+
+	if (sens == NULL) {
+		return SEPOL_OK;
+	}
+
+	cil_list_for_each(curr_sens, sens) {
+		struct cil_multimap_item *sens_multimap_item = curr_sens->data;
+		fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name);
+		if (sens_multimap_item->values->head == NULL) 
+			fprintf(file_arr[SENS], ";\n");
+		else {
+			struct cil_list_item *curr_sensalias;
+			fprintf(file_arr[SENS], " alias");
+			cil_list_for_each(curr_sensalias, sens_multimap_item->values) {
+				fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name);
+			}
+			fprintf(file_arr[SENS], ";\n"); 
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats)
+{
+	cil_expr_to_policy(file_arr, file_index, cats->datum_expr);
+}
+
+void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level)
+{
+	char *sens_str = level->sens->datum.name;
+
+	fprintf(file_arr[file_index], "%s", sens_str);
+	if (level->cats != NULL) {
+		fprintf(file_arr[file_index], ":");
+		cil_cats_to_policy(file_arr, file_index, level->cats);
+	}
+}
+
+void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange)
+{
+	struct cil_level *low = lvlrange->low;
+	struct cil_level *high = lvlrange->high;
+
+	cil_level_to_policy(file_arr, file_index, low);
+	fprintf(file_arr[file_index], "-");
+	cil_level_to_policy(file_arr, file_index, high);
+}
+
+void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context)
+{
+	char *user_str = ((struct cil_symtab_datum*)context->user)->name;
+	char *role_str = ((struct cil_symtab_datum*)context->role)->name;
+	char *type_str = ((struct cil_symtab_datum*)context->type)->name;
+	struct cil_levelrange *lvlrange = context->range;
+
+	fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str);
+	cil_levelrange_to_policy(file_arr, file_index, lvlrange);
+}
+
+void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list)
+{
+	struct cil_list_item *curr;
+
+	fprintf(file_arr[file_index], " {");
+	cil_list_for_each(curr, list) {
+		switch (curr->flavor) {
+		case CIL_LIST:
+			cil_perms_to_policy(file_arr, file_index, curr->data);
+			break;
+		case CIL_STRING:
+			fprintf(file_arr[file_index], " %s", (char *)curr->data);
+			break;
+		case CIL_DATUM:
+			fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name);
+			break;
+		case CIL_OP: {
+			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+			char *op_str = NULL;
+
+			switch (op_flavor) {
+			case CIL_AND:
+				op_str = CIL_KEY_AND;
+				break;
+			case CIL_OR:
+				op_str = CIL_KEY_OR;
+				break;
+			case CIL_NOT:
+				op_str = CIL_KEY_NOT;
+				break;
+			case CIL_ALL:
+				op_str = CIL_KEY_ALL;
+				break;
+			case CIL_XOR:
+				op_str = CIL_KEY_XOR;
+				break;
+			default:
+				cil_log(CIL_ERR, "Unknown operator in expression\n");
+				break;
+			}
+			fprintf(file_arr[file_index], " %s", op_str);
+			break;
+		}
+		default:
+			cil_log(CIL_ERR, "Unknown flavor in expression\n");
+			break;
+		}
+	}
+	fprintf(file_arr[file_index], " }");
+}
+
+void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr)
+{
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name);
+				cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms);
+				fprintf(file_arr[CONSTRAINS], "\n\t");
+				cil_expr_to_policy(file_arr, CONSTRAINS, expr);
+				fprintf(file_arr[CONSTRAINS], ";\n");
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr);
+				}
+			}	
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr);
+		}
+	}
+}
+
+void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor)
+{
+	char *kind = NULL;
+
+	if (flavor == CIL_CONSTRAIN) {
+		kind = CIL_KEY_CONSTRAIN;
+	} else if (flavor == CIL_MLSCONSTRAIN) {
+		kind = CIL_KEY_MLSCONSTRAIN;
+	}
+
+	cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr);
+}
+
+void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms)
+{
+	struct cil_list_item *i;
+
+	cil_list_for_each(i, classperms) {
+		if (i->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = i->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name);
+				cil_perms_to_policy(file_arr, file_index, cp->perms);
+				fprintf(file_arr[file_index], ";\n");
+			} else { /* MAP */
+				struct cil_list_item *j = NULL;
+				cil_list_for_each(j, cp->perms) {
+					struct cil_perm *cmp = j->data;
+					cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms);
+				}
+			}
+		} else { /* SET */
+			struct cil_list_item *j;
+			struct cil_classperms_set *cp_set = i->data;
+			struct cil_classpermission *cp = cp_set->set;
+			cil_list_for_each(j, cp->classperms) {
+				cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data);
+			}
+		}
+	}
+}
+
+int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule)
+{
+	const char *kind_str = NULL;
+	const char *src_str = DATUM(rule->src)->name;
+	const char *tgt_str = DATUM(rule->tgt)->name;
+
+
+	switch (rule->rule_kind) {
+	case CIL_AVRULE_ALLOWED:
+		kind_str = "allow";
+		break;
+	case CIL_AVRULE_AUDITALLOW:
+		kind_str = "auditallow";
+		break;
+	case CIL_AVRULE_DONTAUDIT:
+		kind_str = "dontaudit";
+		break;
+	case CIL_AVRULE_NEVERALLOW:
+		kind_str = "neverallow";
+		break;
+	default :
+		cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n",
+				rule->rule_kind, src_str, tgt_str);
+		return SEPOL_ERR;
+	}
+
+	cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->perms.classperms);
+
+	return SEPOL_OK;
+}
+
+int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule)
+{
+	char *src_str = ((struct cil_symtab_datum*)rule->src)->name;
+	char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name;
+	char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name;
+	char *result_str = ((struct cil_symtab_datum*)rule->result)->name;
+		
+	switch (rule->rule_kind) {
+	case CIL_TYPE_TRANSITION:
+		fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
+		break;
+	case CIL_TYPE_CHANGE:
+		fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str);
+		break;
+	case CIL_TYPE_MEMBER:
+		fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
+		break;
+	default:
+		cil_log(CIL_INFO, "Unknown type_rule\n");
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans)
+{
+	char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name;
+	char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name;
+	char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name;
+	char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name;
+
+	fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str);
+	return SEPOL_OK;
+}
+
+static int cil_expr_to_string(struct cil_list *expr, char **out)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	char *stack[COND_EXPR_MAXDEPTH] = {};
+	int pos = 0;
+	int i;
+
+	cil_list_for_each(curr, expr) {
+		if (pos > COND_EXPR_MAXDEPTH) {
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		switch (curr->flavor) {
+		case CIL_LIST:
+			rc = cil_expr_to_string(curr->data, &stack[pos]);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			pos++;
+			break;
+		case CIL_STRING:
+			stack[pos] = curr->data;
+			pos++;
+			break;
+		case CIL_DATUM:
+			stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
+			pos++;
+			break;
+		case CIL_OP: {
+			int len;
+			char *expr_str;
+			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+			char *op_str = NULL;
+
+			if (pos == 0) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			switch (op_flavor) {
+			case CIL_AND:
+				op_str = CIL_KEY_AND;
+				break;
+			case CIL_OR:
+				op_str = CIL_KEY_OR;
+				break;
+			case CIL_NOT:
+				op_str = CIL_KEY_NOT;
+				break;
+			case CIL_ALL:
+				op_str = CIL_KEY_ALL;
+				break;
+			case CIL_EQ:
+				op_str = CIL_KEY_EQ;
+				break;
+			case CIL_NEQ:
+				op_str = CIL_KEY_NEQ;
+				break;
+			case CIL_XOR:
+				op_str = CIL_KEY_XOR;
+				break;
+			case CIL_CONS_DOM:
+				op_str = CIL_KEY_CONS_DOM;
+				break;
+			case CIL_CONS_DOMBY:
+				op_str = CIL_KEY_CONS_DOMBY;
+				break;
+			case CIL_CONS_INCOMP:
+				op_str = CIL_KEY_CONS_INCOMP;
+				break;
+			default:
+				cil_log(CIL_ERR, "Unknown operator in expression\n");
+				goto exit;
+				break;
+			}
+			if (op_flavor == CIL_NOT) {
+				len = strlen(stack[pos-1]) + strlen(op_str) + 4;
+				expr_str = cil_malloc(len);
+				snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
+				free(stack[pos-1]);
+				stack[pos-1] = NULL;
+				pos--;
+			} else {
+				if (pos < 2) {
+					rc = SEPOL_ERR;
+					goto exit;
+				}
+				len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
+				expr_str = cil_malloc(len);
+				snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]);
+				free(stack[pos-2]);
+				free(stack[pos-1]);
+				stack[pos-2] = NULL;
+				stack[pos-1] = NULL;
+				pos -= 2;
+			}
+			stack[pos] = expr_str;
+			pos++;
+			break;
+		}
+		case CIL_CONS_OPERAND: {
+			enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
+			char *operand_str = NULL;
+			switch (operand_flavor) {
+			case CIL_CONS_U1:
+				operand_str = CIL_KEY_CONS_U1;
+				break;
+			case CIL_CONS_U2:
+				operand_str = CIL_KEY_CONS_U2;
+				break;
+			case CIL_CONS_U3:
+				operand_str = CIL_KEY_CONS_U3;
+				break;
+			case CIL_CONS_T1:
+				operand_str = CIL_KEY_CONS_T1;
+				break;
+			case CIL_CONS_T2:
+				operand_str = CIL_KEY_CONS_T2;
+				break;
+			case CIL_CONS_T3:
+				operand_str = CIL_KEY_CONS_T3;
+				break;
+			case CIL_CONS_R1:
+				operand_str = CIL_KEY_CONS_R1;
+				break;
+			case CIL_CONS_R2:
+				operand_str = CIL_KEY_CONS_R2;
+				break;
+			case CIL_CONS_R3:
+				operand_str = CIL_KEY_CONS_R3;
+				break;
+			case CIL_CONS_L1:
+				operand_str = CIL_KEY_CONS_L1;
+				break;
+			case CIL_CONS_L2:
+				operand_str = CIL_KEY_CONS_L2;
+				break;
+			case CIL_CONS_H1:
+				operand_str = CIL_KEY_CONS_H1;
+				break;
+			case CIL_CONS_H2:
+				operand_str = CIL_KEY_CONS_H2;
+				break;
+			default:
+				cil_log(CIL_ERR, "Unknown operand in expression\n");
+				goto exit;
+				break;
+			}
+			stack[pos] = operand_str;
+			pos++;
+			break;
+		}
+		default:
+			cil_log(CIL_ERR, "Unknown flavor in expression\n");
+			goto exit;
+			break;
+		}
+	}
+
+	*out = stack[0];
+
+	return SEPOL_OK;
+
+exit:
+	for (i = 0; i < pos; i++) {
+		free(stack[i]);
+	}
+	return rc;
+}
+
+int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr)
+{
+	int rc = SEPOL_ERR;
+	char *str_out;
+
+	rc = cil_expr_to_string(expr, &str_out);
+	if (rc != SEPOL_OK) {
+		goto out;
+	}
+	fprintf(file_arr[file_index], "%s", str_out);
+	free(str_out);
+
+	return SEPOL_OK;
+
+out:
+	return rc;
+}
+
+int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_booleanif *args;
+	FILE **file_arr;
+	uint32_t *file_index;
+
+	args = extra_args;
+	file_arr = args->file_arr;
+	file_index = args->file_index;
+
+	switch (node->flavor) {
+	case CIL_AVRULE:
+		rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc);
+			return rc;
+		}
+		break;
+	case CIL_TYPE_RULE:
+		rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc);
+			return rc;
+		}
+		break;
+	case CIL_FALSE:
+		fprintf(file_arr[*file_index], "else {\n");
+		break;
+	case CIL_TRUE:
+		break;
+	default:
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args)
+{
+	struct cil_args_booleanif *args;
+	FILE **file_arr;
+	uint32_t *file_index;
+
+	args = extra_args;
+	file_arr = args->file_arr;
+	file_index = args->file_index;
+
+	if (node->parent->flavor == CIL_FALSE) {
+		fprintf(file_arr[*file_index], "}\n");
+	}
+	
+	return SEPOL_OK;
+}
+
+int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_booleanif *bif = node->data;
+	struct cil_list *expr = bif->datum_expr;
+	struct cil_args_booleanif extra_args;
+	struct cil_tree_node *true_node = NULL;
+	struct cil_tree_node *false_node = NULL;
+	struct cil_condblock *cb = NULL;
+
+	extra_args.file_arr = file_arr;
+	extra_args.file_index = &file_index;;
+
+	fprintf(file_arr[file_index], "if ");
+
+	rc = cil_expr_to_policy(file_arr, file_index, expr);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to write expression\n");
+		return rc;
+	}
+
+	if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) {
+		cb = node->cl_head->data;
+		if (cb->flavor == CIL_CONDTRUE) {
+			true_node = node->cl_head;
+		} else if (cb->flavor == CIL_CONDFALSE) {
+			false_node = node->cl_head;
+		}
+	}
+
+	if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) {
+		cb = node->cl_head->next->data;
+		if (cb->flavor == CIL_CONDTRUE) {
+			true_node = node->cl_head->next;
+		} else if (cb->flavor == CIL_CONDFALSE) {
+			false_node = node->cl_head->next;
+		}
+	}
+
+	fprintf(file_arr[file_index], "{\n");
+	if (true_node != NULL) {
+		rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc);
+			return rc;
+		}
+	}
+	fprintf(file_arr[file_index], "}\n");
+
+	if (false_node != NULL) {
+		fprintf(file_arr[file_index], "else {\n");
+		rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc);
+			return rc;
+		}
+		fprintf(file_arr[file_index], "}\n");
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) 
+{
+	uint32_t flavor = current->flavor;
+	int rc = SEPOL_ERR;
+
+	switch(flavor) {
+	case CIL_TYPEATTRIBUTE:
+		fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	case CIL_TYPE:
+		fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	case CIL_TYPEALIAS: {
+		struct cil_alias *alias = current->data;
+		fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	}
+	case CIL_TYPEBOUNDS: {
+		struct cil_bounds *bnds = current->data;
+		fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str);
+		break;
+	}
+	case CIL_TYPEPERMISSIVE: {
+		struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data;
+		fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name);
+		break;
+	}
+	case CIL_ROLE:
+		fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	case CIL_BOOL: {
+		const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false";
+		fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean);
+		break;
+	}
+	case CIL_COMMON:
+		fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name);
+
+		if (current->cl_head != NULL) {
+			current = current->cl_head;
+			fprintf(file_arr[COMMONS], " {");
+		} else {
+			cil_log(CIL_INFO, "No permissions given\n");
+			return SEPOL_ERR;
+		}
+
+		while (current != NULL) {
+			if (current->flavor == CIL_PERM) {
+				fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name);
+			} else {
+				cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor);
+				return SEPOL_ERR;
+			}
+			current = current->next;
+		}
+		fprintf(file_arr[COMMONS], "}\n");
+
+		return SEPOL_DONE;
+	case CIL_AVRULE: {
+		struct cil_avrule *avrule = (struct cil_avrule*)current->data;
+		rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to write avrule to policy\n");
+			return rc;
+		}
+		break;
+	}
+	case CIL_TYPE_RULE: {
+		struct cil_type_rule *rule = (struct cil_type_rule*)current->data;
+		rc = cil_typerule_to_policy(file_arr, ALLOWS, rule);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to write type rule to policy\n");
+			return rc;
+		}
+		break;
+	}
+	case CIL_NAMETYPETRANSITION: {
+		struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data;
+		rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n");
+			return rc;
+		}
+	}
+	case CIL_ROLETRANSITION: {
+		struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data;
+		char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name;
+		char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name;
+		char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name;
+		char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name;
+		
+		fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str);
+		break;
+	}
+	case CIL_ROLEALLOW: {
+		struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data;
+		char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name;
+		char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name;
+
+		fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str);
+		break;
+	}
+	case CIL_ROLETYPE: {
+		struct cil_roletype *roletype = (struct cil_roletype*)current->data;
+		char *role_str = ((struct cil_symtab_datum*)roletype->role)->name;
+		char *type_str = ((struct cil_symtab_datum*)roletype->type)->name;
+
+		fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str);
+		break;
+	}
+	case CIL_LEVEL:
+		fprintf(file_arr[LEVELS], "level ");
+		cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data);
+			fprintf(file_arr[LEVELS], ";\n");
+			break;
+	case CIL_CONSTRAIN:
+		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
+		break;
+	case CIL_MLSCONSTRAIN:
+		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
+		break;
+	case CIL_VALIDATETRANS: {
+		struct cil_validatetrans *vt = current->data;
+		fprintf(file_arr[CONSTRAINS], "validatetrans");
+		fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name);
+		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
+		fprintf(file_arr[CONSTRAINS], ";\n");
+		break;
+	}
+	case CIL_MLSVALIDATETRANS: {
+		struct cil_validatetrans *vt = current->data;
+		fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans");
+		fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name);
+		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
+		fprintf(file_arr[CONSTRAINS], ";\n");
+		break;
+	}
+	case CIL_SID:
+		fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	case CIL_SIDCONTEXT: {
+		struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data;
+		fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str);
+		cil_context_to_policy(file_arr, SIDS, sidcon->context);
+		fprintf(file_arr[SIDS], "\n");
+		break;
+	}
+	case CIL_POLICYCAP:
+		fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+		break;
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_genpolicy *args = NULL;
+	struct cil_list *users = NULL;
+	struct cil_list *sens = NULL;
+	struct cil_list *cats = NULL;
+	FILE **file_arr = NULL;
+
+	if (extra_args == NULL) {
+		return SEPOL_ERR;
+	}
+
+	*finished = CIL_TREE_SKIP_NOTHING;
+
+	args = extra_args;
+	users = args->users;
+	sens = args->sens;
+	cats = args->cats;
+	file_arr = args->file_arr;
+
+	if (node->cl_head != NULL) {
+		if (node->flavor == CIL_MACRO) {
+			*finished = CIL_TREE_SKIP_HEAD;
+			return SEPOL_OK;
+		}
+
+		if (node->flavor == CIL_BOOLEANIF) {
+			rc = cil_booleanif_to_policy(file_arr, CONDS, node);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to write booleanif contents to file\n");
+				return rc;
+			}
+			*finished = CIL_TREE_SKIP_HEAD;
+			return SEPOL_OK;
+		}
+
+		if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+			return SEPOL_OK;
+		}
+
+		if (node->flavor != CIL_ROOT) {
+			rc = cil_name_to_policy(file_arr, node);
+			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
+				cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor);
+				return SEPOL_ERR;
+			}
+		}
+	} else {
+		switch (node->flavor) {
+		case CIL_USER:
+			cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
+			break;
+		case CIL_CATALIAS: {
+			struct cil_alias *alias = node->data;
+			struct cil_symtab_datum *datum = alias->actual;
+			cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
+		}
+			break;
+		case CIL_SENSALIAS: {
+			struct cil_alias *alias = node->data;
+			struct cil_symtab_datum *datum = alias->actual;
+			cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
+		}
+			break;
+		default:
+			rc = cil_name_to_policy(file_arr, node);
+			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
+				cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
+				return SEPOL_ERR;
+			}
+			break;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_gen_policy(struct cil_db *db)
+{
+	struct cil_tree_node *curr = db->ast->root;
+	struct cil_list_item *item;
+	int rc = SEPOL_ERR;
+	FILE *policy_file;
+	FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
+	char *file_path_arr[NUM_POLICY_FILES];
+	char temp[32];
+
+	struct cil_list *users = NULL;
+	struct cil_list *cats = NULL;
+	struct cil_list *sens = NULL;
+	struct cil_args_genpolicy extra_args;
+
+	cil_list_init(&users, CIL_LIST_ITEM);
+	cil_list_init(&cats, CIL_LIST_ITEM);
+	cil_list_init(&sens, CIL_LIST_ITEM);
+
+	strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
+	file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_isids-XXXXXX");
+	file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[ISIDS] = cil_strpool_add(temp);
+
+	strcpy(temp,"/tmp/cil_common-XXXXXX");
+	file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[COMMONS] = cil_strpool_add(temp);
+	
+	strcpy(temp, "/tmp/cil_class-XXXXXX");
+	file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[CLASSES] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_interf-XXXXXX");
+	file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[INTERFACES] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_sens-XXXXXX");
+	file_arr[SENS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[SENS] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_cats-XXXXXX");
+	file_arr[CATS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[CATS] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_levels-XXXXXX");
+	file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[LEVELS] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
+	file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
+	file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
+	
+	strcpy(temp, "/tmp/cil_aliases-XXXXXX");
+	file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[ALIASES] = cil_strpool_add(temp);
+	
+	strcpy(temp, "/tmp/cil_allows-XXXXXX");
+	file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[ALLOWS] = cil_strpool_add(temp);
+	
+	strcpy(temp, "/tmp/cil_conds-XXXXXX");
+	file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[CONDS] = cil_strpool_add(temp);
+	
+	strcpy(temp, "/tmp/cil_userroles-XXXXXX");
+	file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[USERROLES] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_sids-XXXXXX");
+	file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[SIDS] = cil_strpool_add(temp);
+
+	strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
+	file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
+	file_path_arr[NETIFCONS] = cil_strpool_add(temp);
+
+	policy_file = fopen("policy.conf", "w+");
+
+	cil_list_for_each(item, db->sidorder) {
+		fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
+	}
+
+	cil_list_for_each(item, db->classorder) {
+		struct cil_class *class = item->data;
+		struct cil_tree_node *node = class->datum.nodes->head->data;
+
+		fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
+
+		fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
+		if (class->common != NULL) {
+			fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
+		}
+		if (node->cl_head != NULL) {
+			struct cil_tree_node *curr_perm = node->cl_head;
+			fprintf(file_arr[CLASSES], "{ ");
+			while (curr_perm != NULL) {
+				fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
+				curr_perm = curr_perm->next;
+			}
+			fprintf(file_arr[CLASSES], "}");
+		}
+		fprintf(file_arr[CLASSES], "\n");
+	}
+
+	if (db->catorder->head != NULL) {
+		cil_list_for_each(item, db->catorder) {
+			cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
+		}
+	}
+
+	if (db->sensitivityorder->head != NULL) {
+		fprintf(file_arr[SENS], "sensitivityorder { ");
+		cil_list_for_each(item, db->sensitivityorder) {
+			fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
+		}
+		fprintf(file_arr[SENS], "};\n");
+	}
+
+	extra_args.users = users;
+	extra_args.sens = sens;
+	extra_args.cats = cats;
+	extra_args.file_arr= file_arr;
+
+	rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error walking tree\n");
+		return rc;
+	}
+
+	rc = cil_netifcon_to_policy(file_arr, db->netifcon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+	
+	rc = cil_genfscon_to_policy(file_arr, db->genfscon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_portcon_to_policy(file_arr, db->portcon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_nodecon_to_policy(file_arr, db->nodecon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_fsuse_to_policy(file_arr, db->fsuse);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return rc;
+	}
+
+	rc = cil_userrole_to_policy(file_arr, users);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return SEPOL_ERR;
+	}
+
+	rc = cil_sens_to_policy(file_arr, sens);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return SEPOL_ERR;
+	}
+
+	rc = cil_cat_to_policy(file_arr, cats);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return SEPOL_ERR;
+	}
+
+	rc = cil_combine_policy(file_arr, policy_file);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Error creating policy.conf\n");
+		return SEPOL_ERR;
+	}
+
+	// Remove temp files
+	int i;
+	for (i=0; i<NUM_POLICY_FILES; i++) {
+		rc = fclose(file_arr[i]);
+		if (rc != 0) {
+			cil_log(CIL_ERR, "Error closing temporary file\n");
+			return SEPOL_ERR;
+		}
+		rc = unlink(file_path_arr[i]);
+		if (rc != 0) {
+			cil_log(CIL_ERR, "Error unlinking temporary files\n");
+			return SEPOL_ERR;
+		}
+	}
+
+	rc = fclose(policy_file);
+	if (rc != 0) {
+		cil_log(CIL_ERR, "Error closing policy.conf\n");
+		return SEPOL_ERR;
+	}
+	free(file_arr);
+	
+	cil_list_destroy(&users, CIL_FALSE);
+	cil_list_destroy(&cats, CIL_FALSE);
+	cil_list_destroy(&sens, CIL_FALSE);
+	
+	return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_policy.h b/libsepol/cil/src/cil_policy.h
new file mode 100644
index 0000000..72cf162
--- /dev/null
+++ b/libsepol/cil/src/cil_policy.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_POLICY_H_
+#define CIL_POLICY_H_
+
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_internal.h"
+
+struct cil_multimap_item {
+	struct cil_symtab_datum *key;
+	struct cil_list *values;
+};
+
+int cil_combine_policy(FILE **file_arr, FILE *policy_file);
+void cil_context_to_policy(FILE **, uint32_t, struct cil_context *);
+int cil_name_to_policy(FILE **, struct cil_tree_node *);
+int cil_gen_policy(struct cil_db *);
+
+#endif
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
new file mode 100644
index 0000000..a694b33
--- /dev/null
+++ b/libsepol/cil/src/cil_post.c
@@ -0,0 +1,2056 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sepol/policydb/conditional.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_post.h"
+#include "cil_policy.h"
+#include "cil_verify.h"
+#include "cil_symtab.h"
+
+static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
+static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
+
+static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
+{
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, list) {
+		switch (curr->flavor) {
+		case CIL_LIST:
+			return CIL_FALSE;
+			break;
+		case CIL_OP:
+			return CIL_FALSE;
+			break;
+		default:
+			if (flavor == CIL_CAT) {
+				struct cil_symtab_datum *d = curr->data;
+				struct cil_tree_node *n = d->nodes->head->data;
+				if (n->flavor == CIL_CATSET) {
+					return CIL_FALSE;
+				}
+			}
+			break;
+		}	
+	}
+	return CIL_TRUE;
+}
+
+void cil_post_fc_fill_data(struct fc_data *fc, char *path)
+{
+	int c = 0;
+	fc->meta = 0;
+	fc->stem_len = 0;
+	fc->str_len = 0;
+	
+	while (path[c] != '\0') {
+		switch (path[c]) {
+		case '.':
+		case '^':
+		case '$':
+		case '?':
+		case '*':
+		case '+':
+		case '|':
+		case '[':
+		case '(':
+		case '{':
+			fc->meta = 1;
+			break;
+		case '\\':
+			c++;
+		default:
+			if (!fc->meta) {
+				fc->stem_len++;
+			}
+			break;
+		}
+		fc->str_len++;
+		c++;
+	}
+}
+
+int cil_post_filecon_compare(const void *a, const void *b)
+{
+	int rc = 0;
+	struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
+	struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
+	struct fc_data *a_data = cil_malloc(sizeof(*a_data));
+	struct fc_data *b_data = cil_malloc(sizeof(*b_data));
+	char *a_path = cil_malloc(strlen(a_filecon->path_str) + 1);
+	a_path[0] = '\0';
+	char *b_path = cil_malloc(strlen(b_filecon->path_str) + 1);
+	b_path[0] = '\0';
+	strcat(a_path, a_filecon->path_str);
+	strcat(b_path, b_filecon->path_str);
+	cil_post_fc_fill_data(a_data, a_path);
+	cil_post_fc_fill_data(b_data, b_path);
+	if (a_data->meta && !b_data->meta) {
+		rc = -1;
+	} else if (b_data->meta && !a_data->meta) {
+		rc = 1;
+	} else if (a_data->stem_len < b_data->stem_len) {
+		rc = -1;
+	} else if (b_data->stem_len < a_data->stem_len) {
+		rc = 1;
+	} else if (a_data->str_len < b_data->str_len) {
+		rc = -1;
+	} else if (b_data->str_len < a_data->str_len) {
+		rc = 1;
+	} else if (a_filecon->type < b_filecon->type) {
+		rc = -1;
+	} else if (b_filecon->type < a_filecon->type) {
+		rc = 1;
+	}
+
+	free(a_path);
+	free(b_path);
+	free(a_data);
+	free(b_data);
+
+	return rc;
+}
+
+int cil_post_portcon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_portcon *aportcon = *(struct cil_portcon**)a;
+	struct cil_portcon *bportcon = *(struct cil_portcon**)b;
+
+	rc = (aportcon->port_high - aportcon->port_low) 
+		- (bportcon->port_high - bportcon->port_low);
+	if (rc == 0) {
+		if (aportcon->port_low < bportcon->port_low) {
+			rc = -1;
+		} else if (bportcon->port_low < aportcon->port_low) {
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
+
+int cil_post_genfscon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_genfscon *agenfscon = *(struct cil_genfscon**)a;
+	struct cil_genfscon *bgenfscon = *(struct cil_genfscon**)b;
+
+	rc = strcmp(agenfscon->fs_str, bgenfscon->fs_str);
+	if (rc == 0) {
+		rc = strcmp(agenfscon->path_str, bgenfscon->path_str);
+	}
+
+	return rc;
+}
+
+int cil_post_netifcon_compare(const void *a, const void *b)
+{
+	struct cil_netifcon *anetifcon = *(struct cil_netifcon**)a;
+	struct cil_netifcon *bnetifcon = *(struct cil_netifcon**)b;
+
+	return  strcmp(anetifcon->interface_str, bnetifcon->interface_str);
+}
+
+int cil_post_nodecon_compare(const void *a, const void *b)
+{
+	struct cil_nodecon *anodecon;
+	struct cil_nodecon *bnodecon;
+	anodecon = *(struct cil_nodecon**)a;
+	bnodecon = *(struct cil_nodecon**)b;
+
+	/* sort ipv4 before ipv6 */
+	if (anodecon->addr->family != bnodecon->addr->family) {
+		if (anodecon->addr->family == AF_INET) {
+			return -1;
+		} else {
+			return 1;
+		}
+	}
+
+	/* most specific netmask goes first, then order by ip addr */
+	if (anodecon->addr->family == AF_INET) {
+		int rc = memcmp(&anodecon->mask->ip.v4, &bnodecon->mask->ip.v4, sizeof(anodecon->mask->ip.v4));
+		if (rc != 0) {
+			return -1 * rc;
+		}
+		return memcmp(&anodecon->addr->ip.v4, &bnodecon->addr->ip.v4, sizeof(anodecon->addr->ip.v4));
+	} else {
+		int rc = memcmp(&anodecon->mask->ip.v6, &bnodecon->mask->ip.v6, sizeof(anodecon->mask->ip.v6));
+		if (rc != 0) {
+			return -1 * rc;
+		}
+		return memcmp(&anodecon->addr->ip.v6, &bnodecon->addr->ip.v6, sizeof(anodecon->addr->ip.v6));
+	}
+}
+
+int cil_post_pirqcon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_pirqcon *apirqcon = *(struct cil_pirqcon**)a;
+	struct cil_pirqcon *bpirqcon = *(struct cil_pirqcon**)b;
+
+	if (apirqcon->pirq < bpirqcon->pirq) {
+		rc = -1;
+	} else if (bpirqcon->pirq < apirqcon->pirq) {
+		rc = 1;
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int cil_post_iomemcon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_iomemcon *aiomemcon = *(struct cil_iomemcon**)a;
+	struct cil_iomemcon *biomemcon = *(struct cil_iomemcon**)b;
+
+	rc = (aiomemcon->iomem_high - aiomemcon->iomem_low) 
+		- (biomemcon->iomem_high - biomemcon->iomem_low);
+	if (rc == 0) {
+		if (aiomemcon->iomem_low < biomemcon->iomem_low) {
+			rc = -1;
+		} else if (biomemcon->iomem_low < aiomemcon->iomem_low) {
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
+
+int cil_post_ioportcon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_ioportcon *aioportcon = *(struct cil_ioportcon**)a;
+	struct cil_ioportcon *bioportcon = *(struct cil_ioportcon**)b;
+
+	rc = (aioportcon->ioport_high - aioportcon->ioport_low) 
+		- (bioportcon->ioport_high - bioportcon->ioport_low);
+	if (rc == 0) {
+		if (aioportcon->ioport_low < bioportcon->ioport_low) {
+			rc = -1;
+		} else if (bioportcon->ioport_low < aioportcon->ioport_low) {
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
+
+int cil_post_pcidevicecon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_pcidevicecon *apcidevicecon = *(struct cil_pcidevicecon**)a;
+	struct cil_pcidevicecon *bpcidevicecon = *(struct cil_pcidevicecon**)b;
+
+	if (apcidevicecon->dev < bpcidevicecon->dev) {
+		rc = -1;
+	} else if (bpcidevicecon->dev < apcidevicecon->dev) {
+		rc = 1;
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int cil_post_devicetreecon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_devicetreecon *adevicetreecon = *(struct cil_devicetreecon**)a;
+	struct cil_devicetreecon *bdevicetreecon = *(struct cil_devicetreecon**)b;
+
+	rc = strcmp(adevicetreecon->path, bdevicetreecon->path);
+
+	return rc;
+}
+
+int cil_post_fsuse_compare(const void *a, const void *b)
+{
+	int rc;
+	struct cil_fsuse *afsuse;
+	struct cil_fsuse *bfsuse;
+	afsuse = *(struct cil_fsuse**)a;
+	bfsuse = *(struct cil_fsuse**)b;
+	if (afsuse->type < bfsuse->type) {
+		rc = -1;
+	} else if (bfsuse->type < afsuse->type) {
+		rc = 1;
+	} else {
+		rc = strcmp(afsuse->fs_str, bfsuse->fs_str);
+	}
+	return rc;
+}
+
+static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	struct cil_db *db = extra_args;
+
+	switch(node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_CLASS: {
+		struct cil_class *class = node->data;
+		if (class->datum.nodes->head->data == node) {
+			// Multiple nodes can point to the same datum. Only count once.
+			db->num_classes++;
+		}
+		break;
+	}
+	case CIL_TYPE: {
+		struct cil_type *type = node->data;
+		if (type->datum.nodes->head->data == node) {
+			// Multiple nodes can point to the same datum. Only count once.
+			type->value = db->num_types;
+			db->num_types++;
+			db->num_types_and_attrs++;
+		}
+		break;
+	}
+	case CIL_TYPEATTRIBUTE: {
+		struct cil_typeattribute *attr = node->data;
+		if (attr->datum.nodes->head->data == node) {
+			// Multiple nodes can point to the same datum. Only count once.
+			db->num_types_and_attrs++;
+		}
+		break;
+	}
+
+	case CIL_ROLE: {
+		struct cil_role *role = node->data;
+		if (role->datum.nodes->head->data == node) {
+			// Multiple nodes can point to the same datum. Only count once.
+			role->value = db->num_roles;
+			db->num_roles++;
+		}
+		break;
+	}
+	case CIL_USER: {
+		struct cil_user *user = node->data;
+		if (user->datum.nodes->head->data == node) {
+			// multiple AST nodes can point to the same cil_user data (like if
+			// copied from a macro). This check ensures we only count the
+			// duplicates once
+			user->value = db->num_users;
+			db->num_users++;
+		}
+		break;
+	}
+	case CIL_NETIFCON:
+		db->netifcon->count++;
+		break;
+	case CIL_GENFSCON:
+		db->genfscon->count++;
+		break;
+	case CIL_FILECON:
+		db->filecon->count++;
+		break;
+	case CIL_NODECON:
+		db->nodecon->count++;
+		break;
+	case CIL_PORTCON:
+		db->portcon->count++;
+		break;
+	case CIL_PIRQCON:
+		db->pirqcon->count++;
+		break;
+	case CIL_IOMEMCON:
+		db->iomemcon->count++;
+		break;
+	case CIL_IOPORTCON:
+		db->ioportcon->count++;
+		break;
+	case CIL_PCIDEVICECON:
+		db->pcidevicecon->count++;
+		break;	
+	case CIL_DEVICETREECON:
+		db->devicetreecon->count++;
+		break;
+	case CIL_FSUSE:
+		db->fsuse->count++;
+		break;
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __cil_post_db_array_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	struct cil_db *db = extra_args;
+
+	switch(node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_TYPE: {
+		struct cil_type *type = node->data;
+		if (db->val_to_type == NULL) {
+			db->val_to_type = cil_malloc(sizeof(*db->val_to_type) * db->num_types);
+		}
+		db->val_to_type[type->value] = type;
+		break;
+	}
+	case CIL_ROLE: {
+		struct cil_role *role = node->data;
+		if (db->val_to_role == NULL) {
+			db->val_to_role = cil_malloc(sizeof(*db->val_to_role) * db->num_roles);
+		}
+		db->val_to_role[role->value] = role;
+		break;
+	}
+	case CIL_USER: {
+		struct cil_user *user= node->data;
+		if (db->val_to_user == NULL) {
+			db->val_to_user = cil_malloc(sizeof(*db->val_to_user) * db->num_users);
+		}
+		db->val_to_user[user->value] = user;
+		break;
+	}
+	case CIL_USERPREFIX: {
+		cil_list_append(db->userprefixes, CIL_USERPREFIX, node->data);
+		break;
+	}
+	case CIL_SELINUXUSER: {
+		cil_list_prepend(db->selinuxusers, CIL_SELINUXUSER, node->data);
+		break;
+	}
+	case CIL_SELINUXUSERDEFAULT: {
+		cil_list_append(db->selinuxusers, CIL_SELINUXUSERDEFAULT, node->data);
+		break;
+	}
+	case CIL_NETIFCON: {
+		struct cil_sort *sort = db->netifcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_FSUSE: {
+		struct cil_sort *sort = db->fsuse;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_GENFSCON: {
+		struct cil_sort *sort = db->genfscon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_FILECON: {
+		struct cil_sort *sort = db->filecon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+		sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_NODECON: {
+		struct cil_sort *sort = db->nodecon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_PORTCON: {
+		struct cil_sort *sort = db->portcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_PIRQCON: {
+		struct cil_sort *sort = db->pirqcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_IOMEMCON: {
+		struct cil_sort *sort = db->iomemcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_IOPORTCON: {
+		struct cil_sort *sort = db->ioportcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_PCIDEVICECON: {
+		struct cil_sort *sort = db->pcidevicecon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	case CIL_DEVICETREECON: {
+		struct cil_sort *sort = db->devicetreecon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+		if (sort->array == NULL) {
+			sort->array = cil_malloc(sizeof(*sort->array)*count);
+		}
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __evaluate_type_expression(struct cil_typeattribute *attr, struct cil_db *db)
+{
+	int rc;
+
+	attr->types = cil_malloc(sizeof(*attr->types));
+	rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->types, db->num_types, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to expand type attribute to bitmap\n");
+		ebitmap_destroy(attr->types);
+		free(attr->types);
+		attr->types = NULL;
+	}
+	return rc;
+}
+
+static int __cil_type_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	ebitmap_init(bitmap);
+
+	if (node->flavor == CIL_TYPEATTRIBUTE) {
+		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+		if (attr->types == NULL) {
+			rc = __evaluate_type_expression(attr, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		ebitmap_union(bitmap, attr->types);
+	} else if (node->flavor == CIL_TYPEALIAS) {
+		struct cil_alias *alias = (struct cil_alias *)datum;
+		struct cil_type *type = alias->actual;
+		if (ebitmap_set_bit(bitmap, type->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set type bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	} else {
+		struct cil_type *type = (struct cil_type *)datum;
+		if (ebitmap_set_bit(bitmap, type->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set type bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __evaluate_user_expression(struct cil_userattribute *attr, struct cil_db *db)
+{
+	int rc;
+
+	attr->users = cil_malloc(sizeof(*attr->users));
+	rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->users, db->num_users, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to expand user attribute to bitmap\n");
+		ebitmap_destroy(attr->users);
+		free(attr->users);
+		attr->users = NULL;
+	}
+	return rc;
+}
+
+static int __cil_user_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *node = datum->nodes->head->data;
+	struct cil_userattribute *attr = NULL;
+	struct cil_user *user = NULL;
+
+	ebitmap_init(bitmap);
+
+	if (node->flavor == CIL_USERATTRIBUTE) {
+		attr = (struct cil_userattribute *)datum;
+		if (attr->users == NULL) {
+			rc = __evaluate_user_expression(attr, db);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+		ebitmap_union(bitmap, attr->users);
+	} else {
+		user = (struct cil_user *)datum;
+		if (ebitmap_set_bit(bitmap, user->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set user bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __evaluate_role_expression(struct cil_roleattribute *attr, struct cil_db *db)
+{
+	int rc;
+
+	attr->roles = cil_malloc(sizeof(*attr->roles));
+	rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->roles, db->num_roles, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to expand role attribute to bitmap\n");
+		ebitmap_destroy(attr->roles);
+		free(attr->roles);
+		attr->roles = NULL;
+	}
+	return rc;
+}
+
+static int __cil_role_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	ebitmap_init(bitmap);
+
+	if (node->flavor == CIL_ROLEATTRIBUTE) {
+		struct cil_roleattribute *attr = (struct cil_roleattribute *)datum;
+		if (attr->roles == NULL) {
+			rc = __evaluate_role_expression(attr, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		ebitmap_union(bitmap, attr->roles);
+	} else {
+		struct cil_role *role = (struct cil_role *)datum;
+		if (ebitmap_set_bit(bitmap, role->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set role bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __evaluate_permissionx_expression(struct cil_permissionx *permx, struct cil_db *db)
+{
+	int rc;
+
+	permx->perms = cil_malloc(sizeof(*permx->perms));
+	ebitmap_init(permx->perms);
+
+	rc = __cil_expr_to_bitmap(permx->expr_str, permx->perms, 0x10000, db); // max is one more than 0xFFFF
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to expand permissionx expression\n");
+		ebitmap_destroy(permx->perms);
+		free(permx->perms);
+		permx->perms = NULL;
+	}
+
+	return rc;
+}
+
+static int __cil_permx_str_to_int(char *permx_str, uint16_t *val)
+{
+	char *endptr = NULL;
+	long lval = strtol(permx_str, &endptr, 0);
+
+	if (*endptr != '\0') {
+		cil_log(CIL_ERR, "permissionx value %s not valid number\n", permx_str);
+		goto exit;
+	}
+	if (lval < 0x0000 || lval > 0xFFFF) {
+		cil_log(CIL_ERR, "permissionx value %s must be between 0x0000 and 0xFFFF\n", permx_str);
+		goto exit;
+	}
+
+	*val = (uint16_t)lval;
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_permx_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	uint16_t val;
+
+	ebitmap_init(bitmap);
+
+	rc = __cil_permx_str_to_int((char*)datum, &val);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (ebitmap_set_bit(bitmap, (unsigned int)val, 1)) {
+		cil_log(CIL_ERR, "Failed to set permissionx bit\n");
+		ebitmap_destroy(bitmap);
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_perm_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
+{
+	struct cil_perm *perm = (struct cil_perm *)datum;
+	unsigned int value = perm->value;
+
+	ebitmap_init(bitmap);
+	if (ebitmap_set_bit(bitmap, value, 1)) {
+		cil_log(CIL_INFO, "Failed to set perm bit\n");
+		ebitmap_destroy(bitmap);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __evaluate_cat_expression(struct cil_cats *cats, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	ebitmap_t bitmap;
+	struct cil_list *new;
+	struct cil_list_item *curr;
+
+	if (cats->evaluated == CIL_TRUE) {
+		return SEPOL_OK;
+	}
+
+	if (cil_verify_is_list(cats->datum_expr, CIL_CAT)) {
+		return SEPOL_OK;
+	}
+
+	ebitmap_init(&bitmap);
+	rc = __cil_expr_to_bitmap(cats->datum_expr, &bitmap, db->num_cats, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to expand category expression to bitmap\n");
+		ebitmap_destroy(&bitmap);
+		goto exit;
+	}
+
+	cil_list_init(&new, CIL_CAT);
+
+	cil_list_for_each(curr, db->catorder) {
+		struct cil_cat *cat = curr->data;
+		if (ebitmap_get_bit(&bitmap, cat->value)) {
+			cil_list_append(new, CIL_DATUM, cat);
+		}
+	}
+
+	ebitmap_destroy(&bitmap);
+	cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+	if (new->head != NULL) { 
+		cats->datum_expr = new;
+	} else {
+		/* empty list */
+		cil_list_destroy(&new, CIL_FALSE);
+		cats->datum_expr = NULL;
+	}
+
+	cats->evaluated = CIL_TRUE;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_cat_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	ebitmap_init(bitmap);
+
+	if (node->flavor == CIL_CATSET) {
+		struct cil_catset *catset = (struct cil_catset *)datum;
+		struct cil_list_item *curr;
+		if (catset->cats->evaluated == CIL_FALSE) {
+			rc = __evaluate_cat_expression(catset->cats, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		for (curr = catset->cats->datum_expr->head; curr; curr = curr->next) {
+			struct cil_cat *cat = (struct cil_cat *)curr->data;
+			if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+				cil_log(CIL_ERR, "Failed to set cat bit\n");
+				ebitmap_destroy(bitmap);
+				goto exit;
+			}
+		}
+	} else if (node->flavor == CIL_CATALIAS) {
+		struct cil_alias *alias = (struct cil_alias *)datum;
+		struct cil_cat *cat = alias->actual;
+		if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set cat bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	} else {
+		struct cil_cat *cat = (struct cil_cat *)datum;
+		if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+			cil_log(CIL_ERR, "Failed to set cat bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_cat_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
+{
+	int rc = SEPOL_ERR;
+	struct cil_symtab_datum *d1 = i1->data;
+	struct cil_symtab_datum *d2 = i2->data;
+	struct cil_tree_node *n1 = d1->nodes->head->data;
+	struct cil_tree_node *n2 = d2->nodes->head->data;
+	struct cil_cat *c1 = (struct cil_cat *)d1;
+	struct cil_cat *c2 = (struct cil_cat *)d2;
+	int i;
+
+	if (n1->flavor == CIL_CATSET || n2->flavor == CIL_CATSET) {
+		cil_log(CIL_ERR, "Category sets cannont be used in a category range\n");
+		goto exit;
+	}
+
+	if (n1->flavor == CIL_CATALIAS) {
+		struct cil_alias *alias = (struct cil_alias *)d1;
+		c1 = alias->actual;
+	}
+
+	if (n2->flavor == CIL_CATALIAS) {
+		struct cil_alias *alias = (struct cil_alias *)d2;
+		c2 = alias->actual;
+	}
+
+	for (i = c1->value; i <= c2->value; i++) {
+		if (ebitmap_set_bit(bitmap, i, 1)) {
+			cil_log(CIL_ERR, "Failed to set cat bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_permissionx_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
+{
+	int rc = SEPOL_ERR;
+	char *p1 = i1->data;
+	char *p2 = i2->data;
+	uint16_t v1;
+	uint16_t v2;
+	uint32_t i;
+
+	rc = __cil_permx_str_to_int(p1, &v1);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_permx_str_to_int(p2, &v2);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	for (i = v1; i <= v2; i++) {
+		if (ebitmap_set_bit(bitmap, i, 1)) {
+			cil_log(CIL_ERR, "Failed to set permissionx bit\n");
+			ebitmap_destroy(bitmap);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flavor flavor, ebitmap_t *bitmap, int max, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+
+	if (curr->flavor == CIL_DATUM) {
+		switch (flavor) {
+		case CIL_TYPE:
+			rc = __cil_type_to_bitmap(curr->data, bitmap, db);
+			break;
+		case CIL_ROLE:
+			rc = __cil_role_to_bitmap(curr->data, bitmap, db);
+			break;
+		case CIL_USER:
+			rc = __cil_user_to_bitmap(curr->data, bitmap, db);
+			break;
+		case CIL_PERM:
+			rc = __cil_perm_to_bitmap(curr->data, bitmap, db);
+			break;
+		case CIL_CAT:
+			rc = __cil_cat_to_bitmap(curr->data, bitmap, db);
+			break;
+		default:
+			rc = SEPOL_ERR;
+		}
+	} else if (curr->flavor == CIL_LIST) {
+		struct cil_list *l = curr->data;
+		ebitmap_init(bitmap);
+		rc = __cil_expr_to_bitmap(l, bitmap, max, db);
+		if (rc != SEPOL_OK) {
+			ebitmap_destroy(bitmap);
+		}	
+	} else if (flavor == CIL_PERMISSIONX) {
+		// permissionx expressions aren't resolved into anything, so curr->flavor
+		// is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those
+		rc = __cil_permx_to_bitmap(curr->data, bitmap, db);
+	}
+
+	return rc;
+}
+
+static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	enum cil_flavor flavor;
+	ebitmap_t tmp, b1, b2;
+
+	if (expr == NULL || expr->head == NULL) {
+		return SEPOL_OK;
+	}
+
+	curr = expr->head;
+	flavor = expr->flavor;
+
+	if (curr->flavor == CIL_OP) {
+		enum cil_flavor op = (enum cil_flavor)curr->data;
+
+		if (op == CIL_ALL) {
+			ebitmap_init(&b1); /* all zeros */
+			rc = ebitmap_not(&tmp, &b1, max);
+			ebitmap_destroy(&b1);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to expand 'all' operator\n");
+				ebitmap_destroy(&tmp);
+				goto exit;
+			}
+		} else if (op == CIL_RANGE) {
+			if (flavor == CIL_CAT) {
+				ebitmap_init(&tmp);
+				rc = __cil_cat_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_INFO, "Failed to expand category range\n");
+					ebitmap_destroy(&tmp);
+					goto exit;
+				}
+			} else if (flavor == CIL_PERMISSIONX) {
+				ebitmap_init(&tmp);
+				rc = __cil_permissionx_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_INFO, "Failed to expand category range\n");
+					ebitmap_destroy(&tmp);
+					goto exit;
+				}
+			} else {
+				cil_log(CIL_INFO, "Range operation only supported for categories permissionx\n");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		} else {
+			rc = __cil_expr_to_bitmap_helper(curr->next, flavor, &b1, max, db);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to get first operand bitmap\n");
+				goto exit;
+			}
+
+			if (op == CIL_NOT) {
+				rc = ebitmap_not(&tmp, &b1, max);
+				ebitmap_destroy(&b1);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_INFO, "Failed to NOT bitmap\n");
+					ebitmap_destroy(&tmp);
+					goto exit;
+				}
+			} else {
+				rc = __cil_expr_to_bitmap_helper(curr->next->next, flavor, &b2, max, db);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_INFO, "Failed to get second operand bitmap\n");
+					goto exit;
+				}
+
+				if (op == CIL_OR) {
+					rc = ebitmap_or(&tmp, &b1, &b2);
+				} else if (op == CIL_AND) {
+					rc = ebitmap_and(&tmp, &b1, &b2);
+				} else if (op == CIL_XOR) {
+					rc = ebitmap_xor(&tmp, &b1, &b2);
+				} else {
+					rc = SEPOL_ERR;
+				}
+				ebitmap_destroy(&b1);
+				ebitmap_destroy(&b2);
+				if (rc != SEPOL_OK) {
+					cil_log(CIL_INFO, "Failed to apply operator to bitmaps\n");
+					ebitmap_destroy(&tmp);
+					goto exit;
+				}
+			}
+		}
+	} else {
+		ebitmap_init(&tmp);
+		for (;curr; curr = curr->next) {
+			rc = __cil_expr_to_bitmap_helper(curr, flavor, &b2, max, db);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to get operand in list\n");
+				ebitmap_destroy(&tmp);
+				goto exit;
+			}
+			b1 = tmp;
+			rc = ebitmap_or(&tmp, &b1, &b2);
+			ebitmap_destroy(&b1);
+			ebitmap_destroy(&b2);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_INFO, "Failed to OR operands in list\n");
+				ebitmap_destroy(&tmp);
+				goto exit;
+			}
+
+		}
+	}
+
+	ebitmap_union(out, &tmp);
+	ebitmap_destroy(&tmp);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *expr;
+
+	ebitmap_init(out);
+
+	if (expr_list == NULL) {
+		return SEPOL_OK;
+	}
+
+	cil_list_for_each(expr, expr_list) {
+		ebitmap_t bitmap;
+		struct cil_list *l = (struct cil_list *)expr->data;
+		ebitmap_init(&bitmap);
+		rc = __cil_expr_to_bitmap(l, &bitmap, max, db);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Failed to expand expression list to bitmap\n");
+			ebitmap_destroy(&bitmap);
+			goto exit;
+		}
+		ebitmap_union(out, &bitmap);
+		ebitmap_destroy(&bitmap);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_post_db_attr_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_db *db = extra_args;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO: {
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	}
+	case CIL_TYPEATTRIBUTE: {
+		struct cil_typeattribute *attr = node->data;
+		if (attr->types == NULL) {
+			rc = __evaluate_type_expression(attr, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		break;
+	}
+	case CIL_ROLEATTRIBUTE: {
+		struct cil_roleattribute *attr = node->data;
+		if (attr->roles == NULL) {
+			rc = __evaluate_role_expression(attr, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		break;
+	}
+	case CIL_AVRULEX: {
+		struct cil_avrule *rule = node->data;
+		if (rule->perms.x.permx_str == NULL) {
+			rc = __evaluate_permissionx_expression(rule->perms.x.permx, db);
+			if (rc != SEPOL_OK) goto exit;
+		}
+		break;
+	}
+	case CIL_PERMISSIONX: {
+		struct cil_permissionx *permx = node->data;
+		rc = __evaluate_permissionx_expression(permx, db);
+		if (rc != SEPOL_OK) goto exit;
+		break;
+	}
+	case CIL_USERATTRIBUTE: {
+		struct cil_userattribute *attr = node->data;
+		if (attr->users == NULL) {
+			rc = __evaluate_user_expression(attr, db);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_role_assign_types(struct cil_role *role, struct cil_symtab_datum *datum)
+{
+	struct cil_tree_node *node = datum->nodes->head->data;
+
+	if (role->types == NULL) {
+		role->types = cil_malloc(sizeof(*role->types));
+		ebitmap_init(role->types);
+	}
+
+	if (node->flavor == CIL_TYPE) {
+		struct cil_type *type = (struct cil_type *)datum;
+		if (ebitmap_set_bit(role->types, type->value, 1)) {
+			cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
+			goto exit;
+		}
+	} else if (node->flavor == CIL_TYPEALIAS) {
+		struct cil_alias *alias = (struct cil_alias *)datum;
+		struct cil_type *type = alias->actual;
+		if (ebitmap_set_bit(role->types, type->value, 1)) {
+			cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
+			goto exit;
+		}
+	} else if (node->flavor == CIL_TYPEATTRIBUTE) {
+		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+		ebitmap_union(role->types, attr->types);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_post_db_roletype_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_db *db = extra_args;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO: {
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	}
+	case CIL_ROLETYPE: {
+		struct cil_roletype *roletype = node->data;
+		struct cil_symtab_datum *role_datum = roletype->role;
+		struct cil_symtab_datum *type_datum = roletype->type;
+		struct cil_tree_node *role_node = role_datum->nodes->head->data;
+
+		if (role_node->flavor == CIL_ROLEATTRIBUTE) {
+			struct cil_roleattribute *attr = roletype->role;
+			ebitmap_node_t *rnode;
+			unsigned int i;
+	
+			ebitmap_for_each_bit(attr->roles, rnode, i) {
+				struct cil_role *role = NULL;
+
+				if (!ebitmap_get_bit(attr->roles, i)) {
+					continue;
+				}
+
+				role = db->val_to_role[i];
+
+				rc = __cil_role_assign_types(role, type_datum);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+		} else {
+			struct cil_role *role = roletype->role;
+
+			rc = __cil_role_assign_types(role, type_datum);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_log(CIL_INFO, "cil_post_db_roletype_helper failed\n");
+	return rc;
+}
+
+static int __cil_user_assign_roles(struct cil_user *user, struct cil_symtab_datum *datum)
+{
+	struct cil_tree_node *node = datum->nodes->head->data;
+	struct cil_role *role = NULL;
+	struct cil_roleattribute *attr = NULL;
+
+	if (user->roles == NULL) {
+		user->roles = cil_malloc(sizeof(*user->roles));
+		ebitmap_init(user->roles);
+	}
+
+	if (node->flavor == CIL_ROLE) {
+		role = (struct cil_role *)datum;
+		if (ebitmap_set_bit(user->roles, role->value, 1)) {
+			cil_log(CIL_INFO, "Failed to set bit in user roles bitmap\n");
+			goto exit;
+		}
+	} else if (node->flavor == CIL_ROLEATTRIBUTE) {
+		attr = (struct cil_roleattribute *)datum;
+		ebitmap_union(user->roles, attr->roles);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+static int __cil_post_db_userrole_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_db *db = extra_args;
+	struct cil_block *blk = NULL;
+	struct cil_userrole *userrole = NULL;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *role_datum = NULL;
+	struct cil_tree_node *user_node = NULL;
+	struct cil_userattribute *u_attr = NULL;
+	unsigned int i;
+	struct cil_user *user = NULL;
+	ebitmap_node_t *unode = NULL;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO: {
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	}
+	case CIL_USERROLE: {
+		userrole = node->data;
+		user_datum = userrole->user;
+		role_datum = userrole->role;
+		user_node = user_datum->nodes->head->data;
+
+		if (user_node->flavor == CIL_USERATTRIBUTE) {
+			u_attr = userrole->user;
+
+			ebitmap_for_each_bit(u_attr->users, unode, i) {
+				if (!ebitmap_get_bit(u_attr->users, i)) {
+					continue;
+				}
+
+				user = db->val_to_user[i];
+
+				rc = __cil_user_assign_roles(user, role_datum);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			}
+		} else {
+			user = userrole->user;
+
+			rc = __cil_user_assign_roles(user, role_datum);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_log(CIL_INFO, "cil_post_db_userrole_helper failed\n");
+	return rc;
+}
+
+static int __evaluate_level_expression(struct cil_level *level, struct cil_db *db)
+{
+	if (level->cats != NULL) {
+		return __evaluate_cat_expression(level->cats, db);
+	}
+
+	return SEPOL_OK;
+}
+
+static int __evaluate_levelrange_expression(struct cil_levelrange *levelrange, struct cil_db *db)
+{
+	int rc = SEPOL_OK;
+
+	if (levelrange->low != NULL && levelrange->low->cats != NULL) {
+		rc =  __evaluate_cat_expression(levelrange->low->cats, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+	if (levelrange->high != NULL && levelrange->high->cats != NULL) {
+		rc = __evaluate_cat_expression(levelrange->high->cats, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int __cil_post_db_cat_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_db *db = extra_args;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO: {
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	}
+	case CIL_CATSET: {
+		struct cil_catset *catset = node->data;
+		rc = __evaluate_cat_expression(catset->cats, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_SENSCAT: {
+		struct cil_senscat *senscat = node->data;
+		rc = __evaluate_cat_expression(senscat->cats, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_LEVEL: {
+		rc = __evaluate_level_expression(node->data, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_LEVELRANGE: {
+		rc = __evaluate_levelrange_expression(node->data, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_USER: {
+		struct cil_user *user = node->data;
+		rc = __evaluate_level_expression(user->dftlevel, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rc = __evaluate_levelrange_expression(user->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_SELINUXUSERDEFAULT:
+	case CIL_SELINUXUSER: {
+		struct cil_selinuxuser *selinuxuser = node->data;
+		rc = __evaluate_levelrange_expression(selinuxuser->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_RANGETRANSITION: {
+		struct cil_rangetransition *rangetrans = node->data;
+		rc = __evaluate_levelrange_expression(rangetrans->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_CONTEXT: {
+		struct cil_context *context = node->data;
+		rc = __evaluate_levelrange_expression(context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_SIDCONTEXT: {
+		struct cil_sidcontext *sidcontext = node->data;
+		rc = __evaluate_levelrange_expression(sidcontext->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_FILECON: {
+		struct cil_filecon *filecon = node->data;
+		if (filecon->context) {
+			rc = __evaluate_levelrange_expression(filecon->context->range, db);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+		break;
+	}
+	case CIL_PORTCON: {
+		struct cil_portcon *portcon = node->data;
+		rc = __evaluate_levelrange_expression(portcon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_NODECON: {
+		struct cil_nodecon *nodecon = node->data;
+		rc = __evaluate_levelrange_expression(nodecon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_GENFSCON: {
+		struct cil_genfscon *genfscon = node->data;
+		rc = __evaluate_levelrange_expression(genfscon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_NETIFCON: {
+		struct cil_netifcon *netifcon = node->data;
+		rc = __evaluate_levelrange_expression(netifcon->if_context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rc = __evaluate_levelrange_expression(netifcon->packet_context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_PIRQCON: {
+		struct cil_pirqcon *pirqcon = node->data;
+		rc = __evaluate_levelrange_expression(pirqcon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_IOMEMCON: {
+		struct cil_iomemcon *iomemcon = node->data;
+		rc = __evaluate_levelrange_expression(iomemcon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_IOPORTCON: {
+		struct cil_ioportcon *ioportcon = node->data;
+		rc = __evaluate_levelrange_expression(ioportcon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_PCIDEVICECON: {
+		struct cil_pcidevicecon *pcidevicecon = node->data;
+		rc = __evaluate_levelrange_expression(pcidevicecon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_DEVICETREECON: {
+		struct cil_devicetreecon *devicetreecon = node->data;
+		rc = __evaluate_levelrange_expression(devicetreecon->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_FSUSE: {
+		struct cil_fsuse *fsuse = node->data;
+		rc = __evaluate_levelrange_expression(fsuse->context->range, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+struct perm_to_list {
+	enum cil_flavor flavor;
+	ebitmap_t *perms;
+	struct cil_list *new_list;
+};
+
+static int __perm_bits_to_list(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct perm_to_list *perm_args = (struct perm_to_list *)args;
+	ebitmap_t *perms = perm_args->perms;
+	struct cil_list *new_list = perm_args->new_list;
+	struct cil_perm *perm = (struct cil_perm *)d;
+	unsigned int value = perm->value;
+
+	if (!ebitmap_get_bit(perms, value)) {
+		return SEPOL_OK;
+	}
+
+	cil_list_append(new_list, CIL_DATUM, d);
+
+	return SEPOL_OK;
+}
+
+static int __evaluate_perm_expression(struct cil_list *perms, enum cil_flavor flavor, symtab_t *class_symtab, symtab_t *common_symtab, unsigned int num_perms, struct cil_list **new_list, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct perm_to_list args;
+	ebitmap_t bitmap;
+
+	if (cil_verify_is_list(perms, CIL_PERM)) {
+		return SEPOL_OK;
+	}
+
+	ebitmap_init(&bitmap);
+	rc = __cil_expr_to_bitmap(perms, &bitmap, num_perms, db);
+	if (rc != SEPOL_OK) {
+		ebitmap_destroy(&bitmap);
+		goto exit;
+	}
+
+	cil_list_init(new_list, flavor);
+
+	args.flavor = flavor;
+	args.perms = &bitmap;
+	args.new_list = *new_list;
+
+	cil_symtab_map(class_symtab, __perm_bits_to_list, &args);
+
+	if (common_symtab != NULL) {
+		cil_symtab_map(common_symtab, __perm_bits_to_list, &args);
+	}
+
+	ebitmap_destroy(&bitmap);
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __evaluate_classperms(struct cil_classperms *cp, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_class *class = cp->class;
+	struct cil_class *common = class->common;
+	symtab_t *common_symtab = NULL;
+	struct cil_list *new_list = NULL;
+
+	if (common) {
+		common_symtab = &common->perms;
+	}
+
+	rc = __evaluate_perm_expression(cp->perms, CIL_PERM, &class->perms, common_symtab, class->num_perms, &new_list, db);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (new_list == NULL) {
+		return SEPOL_OK;
+	}
+
+	cil_list_destroy(&cp->perms, CIL_FALSE);
+
+	cp->perms = new_list;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __evaluate_classperms_list(struct cil_list *classperms, struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				rc = __evaluate_classperms(cp, db);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					rc = __evaluate_classperms_list(cmp->classperms, db);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}	
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			rc = __evaluate_classperms_list(cp->classperms, db);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+struct class_map_args {
+	struct cil_db *db;
+	int rc;
+};
+
+static int __evaluate_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct class_map_args *map_args = args;
+	struct cil_perm *cmp = (struct cil_perm *)d;
+
+	int rc = __evaluate_classperms_list(cmp->classperms, map_args->db);
+
+	if (rc != SEPOL_OK) {
+		map_args->rc = rc;
+	}
+
+	return SEPOL_OK;
+}
+
+static int __evaluate_map_class(struct cil_class *mc, struct cil_db *db)
+{
+	struct class_map_args map_args;
+
+	map_args.db = db;
+	map_args.rc = SEPOL_OK;
+	cil_symtab_map(&mc->perms, __evaluate_map_perm_classperms, &map_args);
+
+	return map_args.rc;
+}
+
+static int __cil_post_db_classperms_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_db *db = extra_args;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_MAP_CLASS: {
+		rc = __evaluate_map_class(node->data, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_CLASSPERMISSION: {
+		struct cil_classpermission *cp = node->data;
+		rc = __evaluate_classperms_list(cp->classperms, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_AVRULE: {
+		struct cil_avrule *avrule = node->data;
+		rc = __evaluate_classperms_list(avrule->perms.classperms, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	case CIL_CONSTRAIN:
+	case CIL_MLSCONSTRAIN: {
+		struct cil_constrain *constrain = node->data;
+		rc = __evaluate_classperms_list(constrain->classperms, db);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int cil_post_db(struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_count_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failure during cil databse count helper\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_array_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failure during cil database array helper\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_attr_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to create attribute bitmaps\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_roletype_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed during roletype association\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_userrole_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed during userrole association\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_classperms_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to evaluate class mapping permissions expressions\n");
+		goto exit;
+	}
+
+	rc = cil_tree_walk(db->ast->root, __cil_post_db_cat_helper, NULL, NULL, db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_INFO, "Failed to evaluate category expressions\n");
+		goto exit;
+	}
+
+	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
+	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
+	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
+	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
+	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
+	qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
+	qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
+	qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
+	qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
+	qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
+	qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
+
+exit:
+	return rc;
+}
+
+static int cil_post_verify(struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	int avrule_cnt = 0;
+	int handleunknown = -1;
+	int mls = -1;
+	int nseuserdflt = 0;
+	int pass = 0;
+	struct cil_args_verify extra_args;
+	struct cil_complex_symtab csymtab;
+
+	cil_complex_symtab_init(&csymtab, CIL_CLASS_SYM_SIZE);
+
+	extra_args.db = db;
+	extra_args.csymtab = &csymtab;
+	extra_args.avrule_cnt = &avrule_cnt;
+	extra_args.handleunknown = &handleunknown;
+	extra_args.mls = &mls;
+	extra_args.nseuserdflt = &nseuserdflt;
+	extra_args.pass = &pass;
+
+	for (pass = 0; pass < 2; pass++) {
+		rc = cil_tree_walk(db->ast->root, __cil_verify_helper, NULL, NULL, &extra_args);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to verify cil database\n");
+			goto exit;
+		}
+	}
+
+	if (db->handle_unknown == -1) {
+		if (handleunknown == -1) {
+			db->handle_unknown = SEPOL_DENY_UNKNOWN;
+		} else {
+			db->handle_unknown = handleunknown;
+		}
+	}
+
+	if (db->mls == -1) {
+		if (mls == -1) {
+			db->mls = CIL_FALSE;
+		} else {
+			db->mls = mls;
+		}
+	}
+
+	if (avrule_cnt == 0) {
+		cil_log(CIL_ERR, "Policy must include at least one avrule\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (nseuserdflt > 1) {
+		cil_log(CIL_ERR, "Policy cannot contain more than one selinuxuserdefault, found: %d\n", nseuserdflt);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+exit:
+	cil_complex_symtab_destroy(&csymtab);
+	return rc;
+}
+
+static int cil_pre_verify(struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_verify extra_args;
+
+	extra_args.db = db;
+
+	rc = cil_tree_walk(db->ast->root, __cil_pre_verify_helper, NULL, NULL, &extra_args);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to verify cil database\n");
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int cil_post_process(struct cil_db *db)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_pre_verify(db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to verify cil database\n");
+		goto exit;
+	}
+
+	rc = cil_post_db(db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed post db handling\n");
+		goto exit;
+	}
+
+	rc = cil_post_verify(db);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to verify cil database\n");
+		goto exit;
+	}
+
+exit:
+	return rc;
+		
+}
diff --git a/libsepol/cil/src/cil_post.h b/libsepol/cil/src/cil_post.h
new file mode 100644
index 0000000..74393cc
--- /dev/null
+++ b/libsepol/cil/src/cil_post.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_POST_H_
+#define CIL_POST_H_
+
+struct fc_data {
+	int meta;
+	int stem_len;
+	int str_len;
+};
+
+void cil_post_fc_fill_data(struct fc_data *fc, char *path);
+int cil_post_filecon_compare(const void *a, const void *b);
+int cil_post_portcon_compare(const void *a, const void *b);
+int cil_post_genfscon_compare(const void *a, const void *b);
+int cil_post_netifcon_compare(const void *a, const void *b);
+int cil_post_nodecon_compare(const void *a, const void *b);
+int cil_post_fsuse_compare(const void *a, const void *b);
+
+int cil_post_context_sort(struct cil_db *db);
+
+int cil_post_process(struct cil_db *db);
+
+#endif
diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
new file mode 100644
index 0000000..de00679
--- /dev/null
+++ b/libsepol/cil/src/cil_reset_ast.c
@@ -0,0 +1,571 @@
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+
+static inline void cil_reset_classperms_list(struct cil_list *cp_list);
+static inline void cil_reset_level(struct cil_level *level);
+static inline void cil_reset_levelrange(struct cil_levelrange *levelrange);
+static inline void cil_reset_context(struct cil_context *context);
+
+
+static int __class_reset_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct cil_perm *perm = (struct cil_perm *)d;
+
+	perm->value -= *((int *)args);
+
+	return SEPOL_OK;
+}
+
+static void cil_reset_class(struct cil_class *class)
+{
+	if (class->common != NULL) {
+		struct cil_class *common = class->common;
+		cil_symtab_map(&class->perms, __class_reset_perm_values, &common->num_perms);
+		/* during a re-resolve, we need to reset the common, so a classcommon
+		 * statement isn't seen as a duplicate */
+		class->num_perms -= common->num_perms;
+		class->common = NULL; /* Must make this NULL or there will be an error when re-resolving */
+	}
+	class->ordered = CIL_FALSE;
+}
+
+static void cil_reset_perm(struct cil_perm *perm)
+{
+	cil_reset_classperms_list(perm->classperms);
+}
+
+static inline void cil_reset_classperms(struct cil_classperms *cp)
+{
+	if (cp == NULL) {
+		return;
+	}
+
+	cil_list_destroy(&cp->perms, CIL_FALSE);
+}
+
+static void cil_reset_classpermission(struct cil_classpermission *cp)
+{
+	if (cp == NULL) {
+		return;
+	}
+
+	cil_reset_classperms_list(cp->classperms);
+}
+
+static void cil_reset_classperms_set(struct cil_classperms_set *cp_set)
+{
+	cil_reset_classpermission(cp_set->set);
+}
+
+static inline void cil_reset_classperms_list(struct cil_list *cp_list)
+{
+	struct cil_list_item *curr;
+
+	if (cp_list == NULL) {
+		return;
+	}
+
+	cil_list_for_each(curr, cp_list) {
+		if (curr->flavor == CIL_CLASSPERMS) { /* KERNEL or MAP */
+			cil_reset_classperms(curr->data);
+		} else if (curr->flavor == CIL_CLASSPERMS_SET) { /* SET */
+			cil_reset_classperms_set(curr->data);
+		}
+	}
+}
+
+static void cil_reset_classpermissionset(struct cil_classpermissionset *cps)
+{
+	cil_reset_classperms_list(cps->classperms);
+}
+
+static void cil_reset_classmapping(struct cil_classmapping *cm)
+{
+	cil_reset_classperms_list(cm->classperms);
+}
+
+static void cil_reset_alias(struct cil_alias *alias)
+{
+	/* reset actual to NULL during a re-resolve */
+	alias->actual = NULL;
+}
+
+static void cil_reset_user(struct cil_user *user)
+{
+	/* reset the bounds to NULL during a re-resolve */
+	user->bounds = NULL;
+	user->dftlevel = NULL;
+	user->range = NULL;
+}
+
+static void cil_reset_userattr(struct cil_userattribute *attr)
+{
+	struct cil_list_item *expr = NULL;
+	struct cil_list_item *next = NULL;
+
+	/* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a userattribute statement */
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		expr = attr->expr_list->head;
+		while (expr != NULL) {
+			next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+}
+
+static void cil_reset_userattributeset(struct cil_userattributeset *uas)
+{
+	cil_list_destroy(&uas->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser)
+{
+	if (selinuxuser->range_str == NULL) {
+		cil_reset_levelrange(selinuxuser->range);
+	}
+}
+
+static void cil_reset_role(struct cil_role *role)
+{
+	/* reset the bounds to NULL during a re-resolve */
+	role->bounds = NULL;
+}
+
+static void cil_reset_roleattr(struct cil_roleattribute *attr)
+{
+	/* during a re-resolve, we need to reset the lists of expression stacks  associated with this attribute from a attributeroles statement */
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		struct cil_list_item *expr = attr->expr_list->head;
+		while (expr != NULL) {
+			struct cil_list_item *next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+}
+
+static void cil_reset_roleattributeset(struct cil_roleattributeset *ras)
+{
+	cil_list_destroy(&ras->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_type(struct cil_type *type)
+{
+	/* reset the bounds to NULL during a re-resolve */
+	type->bounds = NULL;
+}
+
+static void cil_reset_typeattr(struct cil_typeattribute *attr)
+{
+	/* during a re-resolve, we need to reset the lists of expression stacks  associated with this attribute from a attributetypes statement */
+	if (attr->expr_list != NULL) {
+		/* we don't want to destroy the expression stacks (cil_list) inside
+		 * this list cil_list_destroy destroys sublists, so we need to do it
+		 * manually */
+		struct cil_list_item *expr = attr->expr_list->head;
+		while (expr != NULL) {
+			struct cil_list_item *next = expr->next;
+			cil_list_item_destroy(&expr, CIL_FALSE);
+			expr = next;
+		}
+		free(attr->expr_list);
+		attr->expr_list = NULL;
+	}
+	attr->used = CIL_FALSE;
+}
+
+static void cil_reset_typeattributeset(struct cil_typeattributeset *tas)
+{
+	cil_list_destroy(&tas->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_avrule(struct cil_avrule *rule)
+{
+	cil_reset_classperms_list(rule->perms.classperms);
+}
+
+static void cil_reset_rangetransition(struct cil_rangetransition *rangetrans)
+{
+	if (rangetrans->range_str == NULL) {
+		cil_reset_levelrange(rangetrans->range);
+	}
+}
+
+static void cil_reset_sens(struct cil_sens *sens)
+{
+	/* during a re-resolve, we need to reset the categories associated with
+	 * this sensitivity from a (sensitivitycategory) statement */
+	cil_list_destroy(&sens->cats_list, CIL_FALSE);
+	sens->ordered = CIL_FALSE;
+}
+
+static void cil_reset_cat(struct cil_cat *cat)
+{
+	cat->ordered = CIL_FALSE;
+}
+
+static inline void cil_reset_cats(struct cil_cats *cats)
+{
+	if (cats != NULL) {
+		cats->evaluated = CIL_FALSE;
+		cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+	}
+}
+
+
+static void cil_reset_senscat(struct cil_senscat *senscat)
+{
+	cil_reset_cats(senscat->cats);
+}
+
+static void cil_reset_catset(struct cil_catset *catset)
+{
+	cil_reset_cats(catset->cats);
+}
+
+static inline void cil_reset_level(struct cil_level *level)
+{
+	cil_reset_cats(level->cats);
+}
+
+static inline void cil_reset_levelrange(struct cil_levelrange *levelrange)
+{
+	if (levelrange->low_str == NULL) {
+		cil_reset_level(levelrange->low);
+	}
+
+	if (levelrange->high_str == NULL) {
+		cil_reset_level(levelrange->high);
+	}
+}
+
+static inline void cil_reset_userlevel(struct cil_userlevel *userlevel)
+{
+	if (userlevel->level_str == NULL) {
+		cil_reset_level(userlevel->level);
+	}
+}
+
+static inline void cil_reset_userrange(struct cil_userrange *userrange)
+{
+	if (userrange->range_str == NULL) {
+		cil_reset_levelrange(userrange->range);
+	}
+}
+
+static inline void cil_reset_context(struct cil_context *context)
+{
+	if (context->range_str == NULL) {
+		cil_reset_levelrange(context->range);
+	}
+}
+
+static void cil_reset_sidcontext(struct cil_sidcontext *sidcontext)
+{
+	if (sidcontext->context_str == NULL) {
+		cil_reset_context(sidcontext->context);
+	}
+}
+
+static void cil_reset_filecon(struct cil_filecon *filecon)
+{
+	if (filecon->context_str == NULL && filecon->context != NULL) {
+		cil_reset_context(filecon->context);
+	}
+}
+
+static void cil_reset_portcon(struct cil_portcon *portcon)
+{
+	if (portcon->context_str == NULL) {
+		cil_reset_context(portcon->context);
+	}
+}
+
+static void cil_reset_nodecon(struct cil_nodecon *nodecon)
+{
+	if (nodecon->context_str == NULL) {
+		cil_reset_context(nodecon->context);
+	}
+}
+
+static void cil_reset_genfscon(struct cil_genfscon *genfscon)
+{
+	if (genfscon->context_str == NULL) {
+		cil_reset_context(genfscon->context);
+	}
+}
+
+static void cil_reset_netifcon(struct cil_netifcon *netifcon)
+{
+	if (netifcon->if_context_str == NULL) {
+		cil_reset_context(netifcon->if_context);
+	}
+
+	if (netifcon->packet_context_str == NULL) {
+		cil_reset_context(netifcon->packet_context);
+	}
+}
+
+static void cil_reset_pirqcon(struct cil_pirqcon *pirqcon)
+{
+	if (pirqcon->context_str == NULL) {
+		cil_reset_context(pirqcon->context);
+	}
+}
+
+static void cil_reset_iomemcon(struct cil_iomemcon *iomemcon)
+{
+	if (iomemcon->context_str == NULL) {
+		cil_reset_context(iomemcon->context);
+	}
+}
+
+static void cil_reset_ioportcon(struct cil_ioportcon *ioportcon)
+{
+	if (ioportcon->context_str == NULL) {
+		cil_reset_context(ioportcon->context);
+	}
+}
+
+static void cil_reset_pcidevicecon(struct cil_pcidevicecon *pcidevicecon)
+{
+	if (pcidevicecon->context_str == NULL) {
+		cil_reset_context(pcidevicecon->context);
+	}
+}
+
+static void cil_reset_devicetreecon(struct cil_devicetreecon *devicetreecon)
+{
+	if (devicetreecon->context_str == NULL) {
+		cil_reset_context(devicetreecon->context);
+	}
+}
+
+static void cil_reset_fsuse(struct cil_fsuse *fsuse)
+{
+	if (fsuse->context_str == NULL) {
+		cil_reset_context(fsuse->context);
+	}
+}
+
+static void cil_reset_sid(struct cil_sid *sid)
+{
+	/* reset the context to NULL during a re-resolve */
+	sid->context = NULL;
+	sid->ordered = CIL_FALSE;
+}
+
+static void cil_reset_constrain(struct cil_constrain *con)
+{
+	cil_reset_classperms_list(con->classperms);
+	cil_list_destroy(&con->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_validatetrans(struct cil_validatetrans *vt)
+{
+	cil_list_destroy(&vt->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_default(struct cil_default *def)
+{
+	cil_list_destroy(&def->class_datums, CIL_FALSE);
+}
+
+static void cil_reset_defaultrange(struct cil_defaultrange *def)
+{
+	cil_list_destroy(&def->class_datums, CIL_FALSE);
+}
+
+static void cil_reset_booleanif(struct cil_booleanif *bif)
+{
+	cil_list_destroy(&bif->datum_expr, CIL_FALSE);
+}
+
+int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+	switch (node->flavor) {
+	case CIL_CLASS:
+		cil_reset_class(node->data);
+		break;
+	case CIL_PERM:
+	case CIL_MAP_PERM:
+		cil_reset_perm(node->data);
+		break;
+	case CIL_CLASSPERMISSION:
+		cil_reset_classpermission(node->data);
+		break;
+	case CIL_CLASSPERMISSIONSET:
+		cil_reset_classpermissionset(node->data);
+		break;
+	case CIL_CLASSMAPPING:
+		cil_reset_classmapping(node->data);
+		break;
+	case CIL_TYPEALIAS:
+	case CIL_SENSALIAS:
+	case CIL_CATALIAS:
+		cil_reset_alias(node->data);
+		break;
+	case CIL_USERRANGE:
+		cil_reset_userrange(node->data);
+		break;
+	case CIL_USERLEVEL:
+		cil_reset_userlevel(node->data);
+		break;
+	case CIL_USER:
+		cil_reset_user(node->data);
+		break;
+	case CIL_USERATTRIBUTE:
+		cil_reset_userattr(node->data);
+		break;
+	case CIL_USERATTRIBUTESET:
+		cil_reset_userattributeset(node->data);
+		break;
+	case CIL_SELINUXUSERDEFAULT:
+	case CIL_SELINUXUSER:
+		cil_reset_selinuxuser(node->data);
+		break;
+	case CIL_ROLE:
+		cil_reset_role(node->data);
+		break;
+	case CIL_ROLEATTRIBUTE:
+		cil_reset_roleattr(node->data);
+		break;
+	case CIL_ROLEATTRIBUTESET:
+		cil_reset_roleattributeset(node->data);
+		break;
+	case CIL_TYPE:
+		cil_reset_type(node->data);
+		break;
+	case CIL_TYPEATTRIBUTE:
+		cil_reset_typeattr(node->data);
+		break;
+	case CIL_TYPEATTRIBUTESET:
+		cil_reset_typeattributeset(node->data);
+		break;
+	case CIL_RANGETRANSITION:
+		cil_reset_rangetransition(node->data);
+		break;
+	case CIL_AVRULE:
+		cil_reset_avrule(node->data);
+		break;
+	case CIL_SENS:
+		cil_reset_sens(node->data);
+		break;
+	case CIL_CAT:
+		cil_reset_cat(node->data);
+		break;
+	case CIL_SENSCAT:
+		cil_reset_senscat(node->data);
+		break;
+	case CIL_CATSET:
+		cil_reset_catset(node->data);
+		break;
+	case CIL_LEVEL:
+		cil_reset_level(node->data);
+		break;
+	case CIL_LEVELRANGE:
+		cil_reset_levelrange(node->data);
+		break;
+	case CIL_CONTEXT:
+		cil_reset_context(node->data);
+		break;
+	case CIL_SIDCONTEXT:
+		cil_reset_sidcontext(node->data);
+		break;
+	case CIL_FILECON:
+		cil_reset_filecon(node->data);
+		break;
+	case CIL_PORTCON:
+		cil_reset_portcon(node->data);
+		break;
+	case CIL_NODECON:
+		cil_reset_nodecon(node->data);
+		break;
+	case CIL_GENFSCON:
+		cil_reset_genfscon(node->data);
+		break;
+	case CIL_NETIFCON:
+		cil_reset_netifcon(node->data);
+		break;
+	case CIL_PIRQCON:
+		cil_reset_pirqcon(node->data);
+		break;
+	case CIL_IOMEMCON:
+		cil_reset_iomemcon(node->data);
+		break;
+	case CIL_IOPORTCON:
+		cil_reset_ioportcon(node->data);
+		break;
+	case CIL_PCIDEVICECON:
+		cil_reset_pcidevicecon(node->data);
+		break;
+	case CIL_DEVICETREECON:
+		cil_reset_devicetreecon(node->data);
+		break;
+	case CIL_FSUSE:
+		cil_reset_fsuse(node->data);
+		break;
+	case CIL_SID:
+		cil_reset_sid(node->data);
+		break;
+	case CIL_CONSTRAIN:
+	case CIL_MLSCONSTRAIN:
+		cil_reset_constrain(node->data);
+		break;
+	case CIL_VALIDATETRANS:
+	case CIL_MLSVALIDATETRANS:
+		cil_reset_validatetrans(node->data);
+		break;
+	case CIL_DEFAULTUSER:
+	case CIL_DEFAULTROLE:
+	case CIL_DEFAULTTYPE:
+		cil_reset_default(node->data);
+		break;
+	case CIL_DEFAULTRANGE:
+		cil_reset_defaultrange(node->data);
+		break;
+	case CIL_BOOLEANIF:
+		cil_reset_booleanif(node->data);
+		break;
+	case CIL_TUNABLEIF:
+	case CIL_CALL:
+		break; /* Not effected by optional block disabling */
+	case CIL_MACRO:
+	case CIL_SIDORDER:
+	case CIL_CLASSORDER:
+	case CIL_CATORDER:
+	case CIL_SENSITIVITYORDER:
+		break; /* Nothing to reset */
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_reset_ast(struct cil_tree_node *current)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_tree_walk(current, __cil_reset_node, NULL, NULL, NULL);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to reset AST\n");
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_reset_ast.h b/libsepol/cil/src/cil_reset_ast.h
new file mode 100644
index 0000000..393ff9e
--- /dev/null
+++ b/libsepol/cil/src/cil_reset_ast.h
@@ -0,0 +1,8 @@
+#ifndef CIL_RESET_AST_H_
+#define CIL_RESET_AST_H_
+
+#include "cil_tree.h"
+
+int cil_reset_ast(struct cil_tree_node *current);
+
+#endif /* CIL_RESET_AST_H_ */
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
new file mode 100644
index 0000000..70e4462
--- /dev/null
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -0,0 +1,4097 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_build_ast.h"
+#include "cil_resolve_ast.h"
+#include "cil_reset_ast.h"
+#include "cil_copy_ast.h"
+#include "cil_verify.h"
+#include "cil_strpool.h"
+#include "cil_symtab.h"
+
+struct cil_args_resolve {
+	struct cil_db *db;
+	enum cil_pass pass;
+	uint32_t *changed;
+	char *last_resolved_name;
+	struct cil_tree_node *optstack;
+	struct cil_tree_node *boolif;
+	struct cil_tree_node *macro;
+	struct cil_tree_node *blockstack;
+	struct cil_list *sidorder_lists;
+	struct cil_list *classorder_lists;
+	struct cil_list *unordered_classorder_lists;
+	struct cil_list *catorder_lists;
+	struct cil_list *sensitivityorder_lists;
+	struct cil_list *in_list;
+};
+
+static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node)
+{
+	/* Currently only used for typetransition file names.
+	   But could be used for any string that is passed as a parameter.
+	*/
+	struct cil_tree_node *parent = ast_node->parent;
+	struct cil_macro *macro = NULL;
+	struct cil_name *name;
+	symtab_t *symtab;
+	enum cil_sym_index sym_index;
+	struct cil_symtab_datum *datum = NULL;
+
+	cil_flavor_to_symtab_index(CIL_NAME, &sym_index);
+	symtab = &((struct cil_root *)db->ast->root->data)->symtab[sym_index];
+
+	cil_symtab_get_datum(symtab, key, &datum);
+	if (datum != NULL) {
+		return (struct cil_name *)datum;
+	}
+
+	if (parent->flavor == CIL_CALL) {
+		struct cil_call *call = parent->data;
+		macro = call->macro;	
+	} else if (parent->flavor == CIL_MACRO) {
+		macro = parent->data;
+	}
+	if (macro != NULL) {
+		struct cil_list_item *item;
+		cil_list_for_each(item, macro->params) {
+			if (((struct cil_param*)item->data)->str == key) {
+				return NULL;
+			}
+		}
+	}
+
+	cil_name_init(&name);
+	cil_symtab_insert(symtab, key, (struct cil_symtab_datum *)name, ast_node);
+	cil_list_append(db->names, CIL_NAME, name);
+
+	return name;
+}
+
+static int __cil_resolve_perms(symtab_t *class_symtab, symtab_t *common_symtab, struct cil_list *perm_strs, struct cil_list **perm_datums)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_init(perm_datums, perm_strs->flavor);
+
+	cil_list_for_each(curr, perm_strs) {
+		if (curr->flavor == CIL_LIST) {
+			struct cil_list *sub_list;
+			rc = __cil_resolve_perms(class_symtab, common_symtab, curr->data, &sub_list);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Failed to resolve permission list\n");
+				goto exit;
+			}
+			cil_list_append(*perm_datums, CIL_LIST, sub_list);
+		} else if (curr->flavor == CIL_STRING) {
+			struct cil_symtab_datum *perm_datum = NULL;
+			rc = cil_symtab_get_datum(class_symtab, curr->data, &perm_datum);
+			if (rc == SEPOL_ENOENT) {
+				if (common_symtab) {
+					rc = cil_symtab_get_datum(common_symtab, curr->data, &perm_datum);
+				}
+			}
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Failed to resolve permission %s\n", (char*)curr->data);
+				goto exit;
+			}
+			cil_list_append(*perm_datums, CIL_DATUM, perm_datum);
+		} else {
+			cil_list_append(*perm_datums, curr->flavor, curr->data);
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_classperms(struct cil_tree_node *current, struct cil_classperms *cp, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_symtab_datum *datum = NULL;
+	symtab_t *common_symtab = NULL;
+	struct cil_class *class;
+
+	rc = cil_resolve_name(current, cp->class_str, CIL_SYM_CLASSES, extra_args, &datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	class = (struct cil_class *)datum;
+
+	if (class->common != NULL) {
+		common_symtab = &class->common->perms;
+	}
+
+	cp->class = class;
+
+	rc = __cil_resolve_perms(&class->perms, common_symtab, cp->perm_strs, &cp->perms);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_classperms_set(struct cil_tree_node *current, struct cil_classperms_set *cp_set, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_symtab_datum *datum = NULL;
+
+	rc = cil_resolve_name(current, cp_set->set_str, CIL_SYM_CLASSPERMSETS, extra_args, &datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	cp_set->set = (struct cil_classpermission*)datum;
+
+	/* This could be an anonymous classpermission */
+	if (datum->name == NULL) {
+		rc = cil_resolve_classperms_list(current, cp_set->set->classperms, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_classperms_list(struct cil_tree_node *current, struct cil_list *cp_list, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, cp_list) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			rc = cil_resolve_classperms(current, curr->data, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		} else {
+			rc = cil_resolve_classperms_set(current, curr->data, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_classpermissionset(struct cil_tree_node *current, struct cil_classpermissionset *cps, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list_item *curr;
+	struct cil_symtab_datum *datum;
+	struct cil_classpermission *cp;
+
+	rc = cil_resolve_name(current, cps->set_str, CIL_SYM_CLASSPERMSETS, args, &datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_classperms_list(current, cps->classperms, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	cp = (struct cil_classpermission *)datum;
+
+	if (cp->classperms == NULL) {
+		cil_list_init(&cp->classperms, CIL_CLASSPERMS);
+	}
+
+	cil_list_for_each(curr, cps->classperms) {
+		cil_list_append(cp->classperms, curr->flavor, curr->data);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_type_used(struct cil_symtab_datum *datum)
+{
+	struct cil_typeattribute *attr = NULL;
+
+	if (FLAVOR(datum) == CIL_TYPEATTRIBUTE) {
+		attr = (struct cil_typeattribute*)datum;
+		attr->used = CIL_TRUE;
+	}
+
+	return 0;
+}
+
+int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args)
+{
+	struct cil_symtab_datum *obj_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, permx->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	permx->obj = (struct cil_class*)obj_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_avrule(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = NULL;
+
+	struct cil_avrule *rule = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *tgt_datum = NULL;
+	struct cil_symtab_datum *permx_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (args != NULL) {
+		db = args->db;
+	}
+
+	rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rule->src = src_datum;
+	if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+		cil_type_used(src_datum);
+	}
+		
+	if (rule->tgt_str == CIL_KEY_SELF) {
+		rule->tgt = db->selftype;
+	} else {
+		rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, args, &tgt_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rule->tgt = tgt_datum;
+		if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+			cil_type_used(tgt_datum);
+		}
+	}
+
+	if (!rule->is_extended) {
+		rc = cil_resolve_classperms_list(current, rule->perms.classperms, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	} else {
+		if (rule->perms.x.permx_str != NULL) {
+			rc = cil_resolve_name(current, rule->perms.x.permx_str, CIL_SYM_PERMX, args, &permx_datum);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			rule->perms.x.permx = (struct cil_permissionx*)permx_datum;
+		} else {
+			rc = cil_resolve_permissionx(current, rule->perms.x.permx, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_type_rule *rule = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *tgt_datum = NULL;
+	struct cil_symtab_datum *obj_datum = NULL;
+	struct cil_symtab_datum *result_datum = NULL;
+	struct cil_tree_node *result_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rule->src = src_datum;
+	cil_type_used(src_datum);
+
+	rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rule->tgt = tgt_datum;
+	cil_type_used(tgt_datum);
+
+	rc = cil_resolve_name(current, rule->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rule->obj = (struct cil_class*)obj_datum;
+
+	rc = cil_resolve_name(current, rule->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	result_node = result_datum->nodes->head->data;
+
+	if (result_node->flavor != CIL_TYPE) {
+		cil_log(CIL_ERR, "Type rule result must be a type [%d]\n",result_node->flavor);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+	rule->result = result_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_typeattributeset *attrtypes = current->data;
+	struct cil_symtab_datum *attr_datum = NULL;
+	struct cil_tree_node *attr_node = NULL;
+	struct cil_typeattribute *attr = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, attrtypes->attr_str, CIL_SYM_TYPES, extra_args, &attr_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	attr_node = attr_datum->nodes->head->data;
+
+	if (attr_node->flavor != CIL_TYPEATTRIBUTE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Attribute type not an attribute\n");
+		goto exit;
+	}
+
+	attr = (struct cil_typeattribute*)attr_datum;
+
+	rc = cil_resolve_expr(CIL_TYPEATTRIBUTESET, attrtypes->str_expr, &attrtypes->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_verify_no_self_reference(attr_datum, attrtypes->datum_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (attr->expr_list == NULL) {
+		cil_list_init(&attr->expr_list, CIL_TYPEATTRIBUTE);
+	}
+
+	cil_list_append(attr->expr_list, CIL_LIST, attrtypes->datum_expr);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor)
+{
+	int rc = SEPOL_ERR;
+	enum cil_sym_index sym_index;
+	struct cil_aliasactual *aliasactual = current->data;
+	struct cil_symtab_datum *alias_datum = NULL;
+	struct cil_symtab_datum *actual_datum = NULL;
+	struct cil_alias *alias;
+
+	rc = cil_flavor_to_symtab_index(flavor, &sym_index);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rc = cil_resolve_name(current, aliasactual->alias_str, sym_index, extra_args, &alias_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_name(current, aliasactual->actual_str, sym_index, extra_args, &actual_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	alias = (struct cil_alias *)alias_datum;
+
+	if (alias->actual != NULL) {
+		cil_log(CIL_ERR, "Alias cannot bind more than one value\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	alias->actual = actual_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor flavor)
+{
+	struct cil_alias *alias = current->data;
+	struct cil_alias *a1 = current->data;
+	struct cil_alias *a2 = current->data;
+	struct cil_tree_node *a1_node = NULL;
+	int steps = 0;
+	int limit = 2;
+
+	if (alias->actual == NULL) {
+		cil_tree_log(current, CIL_ERR, "Alias declared but not used");
+		return SEPOL_ERR;
+	}
+
+	a1_node = a1->datum.nodes->head->data;
+
+	while (flavor != a1_node->flavor) {
+		a1 = a1->actual;
+		a1_node = a1->datum.nodes->head->data;
+		steps += 1;
+
+		if (a1 == a2) {
+			cil_log(CIL_ERR, "Circular alias found: %s ", a1->datum.name);
+			a1 = a1->actual;
+			while (a1 != a2) {
+				cil_log(CIL_ERR, "%s ", a1->datum.name);
+				a1 = a1->actual;
+			}
+			cil_log(CIL_ERR,"\n");
+			return SEPOL_ERR;
+		}
+
+		if (steps == limit) {
+			steps = 0;
+			limit *= 2;
+			a2 = a1;
+		}
+	}
+
+	alias->actual = a1;
+
+	return SEPOL_OK;
+}
+
+int cil_resolve_typepermissive(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_typepermissive *typeperm = current->data;
+	struct cil_symtab_datum *type_datum = NULL;
+	struct cil_tree_node *type_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, typeperm->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	type_node = type_datum->nodes->head->data;
+
+	if (type_node->flavor != CIL_TYPE && type_node->flavor != CIL_TYPEALIAS) {
+		cil_log(CIL_ERR, "Typepermissive must be a type or type alias\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	typeperm->type = type_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_nametypetransition *nametypetrans = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *tgt_datum = NULL;
+	struct cil_symtab_datum *obj_datum = NULL;
+	struct cil_symtab_datum *name_datum = NULL;
+	struct cil_symtab_datum *result_datum = NULL;
+	struct cil_tree_node *result_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, nametypetrans->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	nametypetrans->src = src_datum;
+	cil_type_used(src_datum);
+
+	rc = cil_resolve_name(current, nametypetrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	nametypetrans->tgt = tgt_datum;
+	cil_type_used(tgt_datum);
+
+	rc = cil_resolve_name(current, nametypetrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	nametypetrans->obj = (struct cil_class*)obj_datum;
+
+	nametypetrans->name = __cil_insert_name(args->db, nametypetrans->name_str, current);
+	if (nametypetrans->name == NULL) {
+		rc = cil_resolve_name(current, nametypetrans->name_str, CIL_SYM_NAMES, extra_args, &name_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		nametypetrans->name = (struct cil_name *)name_datum;
+	}
+
+	rc = cil_resolve_name(current, nametypetrans->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	result_node = result_datum->nodes->head->data;
+
+	if (result_node->flavor != CIL_TYPE && result_node->flavor != CIL_TYPEALIAS) {
+		cil_log(CIL_ERR, "typetransition result is not a type or type alias\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+	nametypetrans->result = result_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_rangetransition(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_rangetransition *rangetrans = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *exec_datum = NULL;
+	struct cil_symtab_datum *obj_datum = NULL;
+	struct cil_symtab_datum *range_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, rangetrans->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rangetrans->src = src_datum;
+	cil_type_used(src_datum);
+
+	rc = cil_resolve_name(current, rangetrans->exec_str, CIL_SYM_TYPES, extra_args, &exec_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rangetrans->exec = exec_datum;
+	cil_type_used(exec_datum);
+
+	rc = cil_resolve_name(current, rangetrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	rangetrans->obj = (struct cil_class*)obj_datum;
+
+	if (rangetrans->range_str != NULL) {
+		rc = cil_resolve_name(current, rangetrans->range_str, CIL_SYM_LEVELRANGES, extra_args, &range_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		rangetrans->range = (struct cil_levelrange*)range_datum;
+
+		/* This could still be an anonymous levelrange even if range_str is set, if range_str is a param_str*/
+		if (rangetrans->range->datum.name == NULL) {
+			rc = cil_resolve_levelrange(current, rangetrans->range, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else {
+		rc = cil_resolve_levelrange(current, rangetrans->range, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __class_update_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	struct cil_perm *perm = (struct cil_perm *)d;
+
+	perm->value += *((int *)args);
+
+	return SEPOL_OK;
+}
+
+int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_class *class = NULL;
+	struct cil_class *common = NULL;
+	struct cil_classcommon *clscom = current->data;
+	struct cil_symtab_datum *class_datum = NULL;
+	struct cil_symtab_datum *common_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, clscom->class_str, CIL_SYM_CLASSES, extra_args, &class_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_name(current, clscom->common_str, CIL_SYM_COMMONS, extra_args, &common_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	class = (struct cil_class *)class_datum;
+	common = (struct cil_class *)common_datum;
+	if (class->common != NULL) {
+		cil_log(CIL_ERR, "class cannot be associeated with more than one common\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	class->common = common;
+
+	cil_symtab_map(&class->perms, __class_update_perm_values, &common->num_perms);
+
+	class->num_perms += common->num_perms;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_classmapping(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_classmapping *mapping = current->data;
+	struct cil_class *map = NULL;
+	struct cil_perm *mp = NULL;
+	struct cil_symtab_datum *datum = NULL;
+	struct cil_list_item *curr;
+
+	rc = cil_resolve_name(current, mapping->map_class_str, CIL_SYM_CLASSES, extra_args, &datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	map = (struct cil_class*)datum;
+
+	rc = cil_symtab_get_datum(&map->perms, mapping->map_perm_str, &datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	mp = (struct cil_perm*)datum;
+
+	rc = cil_resolve_classperms_list(current, mapping->classperms, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (mp->classperms == NULL) {
+		cil_list_init(&mp->classperms, CIL_CLASSPERMS);
+	}
+
+	cil_list_for_each(curr, mapping->classperms) {
+		cil_list_append(mp->classperms, curr->flavor, curr->data);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_userrole(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_userrole *userrole = current->data;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *role_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, userrole->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	userrole->user = (struct cil_user*)user_datum;
+
+	rc = cil_resolve_name(current, userrole->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	userrole->role = role_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_userlevel *usrlvl = current->data;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *lvl_datum = NULL;
+	struct cil_user *user = NULL;
+	struct cil_tree_node *user_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, usrlvl->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	user_node = user_datum->nodes->head->data;
+
+	if (user_node->flavor != CIL_USER) {
+		cil_log(CIL_ERR, "Userlevel must be a user\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	user = (struct cil_user*)user_datum;
+
+	if (usrlvl->level_str != NULL) {
+		rc = cil_resolve_name(current, usrlvl->level_str, CIL_SYM_LEVELS, extra_args, &lvl_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		usrlvl->level = (struct cil_level*)lvl_datum;
+		user->dftlevel = usrlvl->level;
+
+		/* This could still be an anonymous level even if level_str is set, if level_str is a param_str*/
+		if (user->dftlevel->datum.name == NULL) {
+			rc = cil_resolve_level(current, user->dftlevel, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (usrlvl->level != NULL) {
+		rc = cil_resolve_level(current, usrlvl->level, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		user->dftlevel = usrlvl->level;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_userrange *userrange = current->data;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *range_datum = NULL;
+	struct cil_user *user = NULL;
+	struct cil_tree_node *user_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, userrange->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	user_node = user_datum->nodes->head->data;
+
+	if (user_node->flavor != CIL_USER) {
+		cil_log(CIL_ERR, "Userrange must be a user: %s\n", user_datum->fqn);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	user = (struct cil_user*)user_datum;
+
+	if (userrange->range_str != NULL) {
+		rc = cil_resolve_name(current, userrange->range_str, CIL_SYM_LEVELRANGES, extra_args, &range_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		userrange->range = (struct cil_levelrange*)range_datum;
+		user->range = userrange->range;
+
+		/* This could still be an anonymous levelrange even if levelrange_str is set, if levelrange_str is a param_str*/
+		if (user->range->datum.name == NULL) {
+			rc = cil_resolve_levelrange(current, user->range, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (userrange->range != NULL) {
+		rc = cil_resolve_levelrange(current, userrange->range, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		user->range = userrange->range;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_userprefix *userprefix = current->data;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_tree_node *user_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, userprefix->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	user_node = user_datum->nodes->head->data;
+
+	if (user_node->flavor != CIL_USER) {
+		cil_log(CIL_ERR, "Userprefix must be a user: %s\n", user_datum->fqn);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	userprefix->user = (struct cil_user*)user_datum;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_selinuxuser *selinuxuser = current->data;
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *lvlrange_datum = NULL;
+	struct cil_tree_node *user_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, selinuxuser->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	user_node = user_datum->nodes->head->data;
+
+	if (user_node->flavor != CIL_USER) {
+		cil_log(CIL_ERR, "Selinuxuser must be a user: %s\n", user_datum->fqn);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	selinuxuser->user = (struct cil_user*)user_datum;
+
+	if (selinuxuser->range_str != NULL) {
+		rc = cil_resolve_name(current, selinuxuser->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		selinuxuser->range = (struct cil_levelrange*)lvlrange_datum;
+
+		/* This could still be an anonymous levelrange even if range_str is set, if range_str is a param_str*/
+		if (selinuxuser->range->datum.name == NULL) {
+			rc = cil_resolve_levelrange(current, selinuxuser->range, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (selinuxuser->range != NULL) {
+		rc = cil_resolve_levelrange(current, selinuxuser->range, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
+int cil_resolve_roletype(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_roletype *roletype = current->data;
+	struct cil_symtab_datum *role_datum = NULL;
+	struct cil_symtab_datum *type_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, roletype->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roletype->role = (struct cil_role*)role_datum;
+
+	rc = cil_resolve_name(current, roletype->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roletype->type = (struct cil_type*)type_datum;
+	cil_type_used(type_datum);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_roletransition *roletrans = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *tgt_datum = NULL;
+	struct cil_symtab_datum *obj_datum = NULL;
+	struct cil_symtab_datum *result_datum = NULL;
+	struct cil_tree_node *node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, roletrans->src_str, CIL_SYM_ROLES, extra_args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roletrans->src = (struct cil_role*)src_datum;
+
+	rc = cil_resolve_name(current, roletrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roletrans->tgt = tgt_datum;
+	cil_type_used(tgt_datum);
+
+	rc = cil_resolve_name(current, roletrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roletrans->obj = (struct cil_class*)obj_datum;
+
+	rc = cil_resolve_name(current, roletrans->result_str, CIL_SYM_ROLES, extra_args, &result_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	node = result_datum->nodes->head->data;
+	if (node->flavor != CIL_ROLE) {
+		rc = SEPOL_ERR;
+		printf("%i\n", node->flavor);
+		cil_log(CIL_ERR, "roletransition must result in a role, but %s is a %s\n", roletrans->result_str, cil_node_to_string(node));
+		goto exit;
+	}
+	roletrans->result = (struct cil_role*)result_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_roleallow(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_roleallow *roleallow = current->data;
+	struct cil_symtab_datum *src_datum = NULL;
+	struct cil_symtab_datum *tgt_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, roleallow->src_str, CIL_SYM_ROLES, extra_args, &src_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roleallow->src = (struct cil_role*)src_datum;
+
+	rc = cil_resolve_name(current, roleallow->tgt_str, CIL_SYM_ROLES, extra_args, &tgt_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	roleallow->tgt = (struct cil_role*)tgt_datum;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_roleattributeset *attrroles = current->data;
+	struct cil_symtab_datum *attr_datum = NULL;
+	struct cil_tree_node *attr_node = NULL;
+	struct cil_roleattribute *attr = NULL;
+
+	rc = cil_resolve_name(current, attrroles->attr_str, CIL_SYM_ROLES, extra_args, &attr_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	attr_node = attr_datum->nodes->head->data;
+
+	if (attr_node->flavor != CIL_ROLEATTRIBUTE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Attribute role not an attribute\n");
+		goto exit;
+	}
+	attr = (struct cil_roleattribute*)attr_datum;
+
+	rc = cil_resolve_expr(CIL_ROLEATTRIBUTESET, attrroles->str_expr, &attrroles->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_verify_no_self_reference(attr_datum, attrroles->datum_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (attr->expr_list == NULL) {
+		cil_list_init(&attr->expr_list, CIL_ROLEATTRIBUTE);
+	}
+
+	cil_list_append(attr->expr_list, CIL_LIST, attrroles->datum_expr);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+struct cil_ordered_list {
+	int merged;
+	struct cil_list *list;
+	struct cil_tree_node *node;
+};
+
+void __cil_ordered_list_init(struct cil_ordered_list **ordered)
+{
+	*ordered = cil_malloc(sizeof(**ordered));
+
+	(*ordered)->merged = CIL_FALSE;
+	(*ordered)->list = NULL;
+	(*ordered)->node = NULL;
+}
+
+void __cil_ordered_list_destroy(struct cil_ordered_list **ordered)
+{
+	cil_list_destroy(&(*ordered)->list, CIL_FALSE);
+	(*ordered)->node = NULL;
+	free(*ordered);
+	*ordered = NULL;
+}
+
+void __cil_ordered_lists_destroy(struct cil_list **ordered_lists)
+{
+	struct cil_list_item *item = NULL;
+
+	if (ordered_lists == NULL || *ordered_lists == NULL) {
+		return;
+	}
+
+	item = (*ordered_lists)->head;
+	while (item != NULL) {
+		struct cil_list_item *next = item->next;
+		struct cil_ordered_list *ordered = item->data;
+		__cil_ordered_list_destroy(&ordered);
+		free(item);
+		item = next;
+	}
+	free(*ordered_lists);
+	*ordered_lists = NULL;
+}
+
+void __cil_ordered_lists_reset(struct cil_list **ordered_lists)
+{
+	__cil_ordered_lists_destroy(ordered_lists);
+	cil_list_init(ordered_lists, CIL_LIST_ITEM);
+}
+
+struct cil_list_item *__cil_ordered_item_insert(struct cil_list *old, struct cil_list_item *curr, struct cil_list_item *item)
+{
+	if (item->flavor == CIL_SID) {
+		struct cil_sid *sid = item->data;
+		if (sid->ordered == CIL_TRUE) {
+			cil_log(CIL_ERR, "SID %s has already been merged into the ordered list\n", sid->datum.name);
+			return NULL;
+		}
+		sid->ordered = CIL_TRUE;
+	} else if (item->flavor == CIL_CLASS) {
+		struct cil_class *class = item->data;
+		if (class->ordered == CIL_TRUE) {
+			cil_log(CIL_ERR, "Class %s has already been merged into the ordered list\n", class->datum.name);
+			return NULL;
+		}
+		class->ordered = CIL_TRUE;
+	} else if (item->flavor == CIL_CAT) {
+		struct cil_cat *cat = item->data;
+		if (cat->ordered == CIL_TRUE) {
+			cil_log(CIL_ERR, "Category %s has already been merged into the ordered list\n", cat->datum.name);
+			return NULL;
+		}
+		cat->ordered = CIL_TRUE;
+	} else if (item->flavor == CIL_SENS) {
+		struct cil_sens *sens = item->data;
+		if (sens->ordered == CIL_TRUE) {
+			cil_log(CIL_ERR, "Sensitivity %s has already been merged into the ordered list\n", sens->datum.name);
+			return NULL;
+		}
+		sens->ordered = CIL_TRUE;
+	}
+
+	return cil_list_insert(old, curr, item->flavor, item->data);
+}
+
+int __cil_ordered_list_insert(struct cil_list *old, struct cil_list_item *ocurr, struct cil_list_item *nstart, struct cil_list_item *nstop)
+{
+	struct cil_list_item *ncurr = NULL;
+
+	for (ncurr = nstart; ncurr != nstop; ncurr = ncurr->next) {
+		ocurr = __cil_ordered_item_insert(old, ocurr, ncurr);
+		if (ocurr == NULL) {
+			return SEPOL_ERR;
+		}
+	}
+	return SEPOL_OK;
+}
+
+struct cil_list_item *__cil_ordered_find_match(struct cil_list_item *t, struct cil_list_item *i)
+{
+	while (i) {
+		if (i->data == t->data) {
+			return i;
+		}
+		i = i->next;
+	}
+	return NULL;
+}
+
+int __cil_ordered_lists_merge(struct cil_list *old, struct cil_list *new)
+{
+	struct cil_list_item *omatch = NULL;
+	struct cil_list_item *ofirst = old->head;
+	struct cil_list_item *ocurr = NULL;
+	struct cil_list_item *oprev = NULL;
+	struct cil_list_item *nmatch = NULL;
+	struct cil_list_item *nfirst = new->head;
+	struct cil_list_item *ncurr = NULL;
+	int rc = SEPOL_ERR;
+
+	if (nfirst == NULL) {
+		return SEPOL_OK;
+	}
+
+	if (ofirst == NULL) {
+		/* First list added */
+		rc = __cil_ordered_list_insert(old, NULL, nfirst, NULL);
+		return rc;
+	}
+
+	/* Find a match between the new list and the old one */
+	for (nmatch = nfirst; nmatch; nmatch = nmatch->next) {
+		omatch = __cil_ordered_find_match(nmatch, ofirst);
+		if (omatch) {
+			break;
+		}
+	}
+
+	if (!nmatch) {
+		/* List cannot be merged yet */
+		return SEPOL_ERR;
+	}
+
+	if (nmatch != nfirst && omatch != ofirst) {
+		/* Potential ordering conflict--try again later */
+		return SEPOL_ERR;
+	}
+
+	if (nmatch != nfirst) {
+		/* Prepend the beginning of the new list up to the first match to the old list */
+		rc = __cil_ordered_list_insert(old, NULL, nfirst, nmatch);
+		if (rc != SEPOL_OK) {
+			return rc;
+		}
+	}
+
+	/* In the overlapping protion, add items from the new list not in the old list */
+	ncurr = nmatch->next;
+	ocurr = omatch->next;
+	oprev = omatch;
+	while (ncurr && ocurr) {
+		if (ncurr->data == ocurr->data) {
+			oprev = ocurr;
+			ocurr = ocurr->next;
+			ncurr = ncurr->next;
+		} else {
+			/* Handle gap in old: old = (A C)  new = (A B C) */
+			nmatch = __cil_ordered_find_match(ocurr, ncurr->next);
+			if (nmatch) {
+				rc = __cil_ordered_list_insert(old, oprev, ncurr, nmatch);
+				if (rc != SEPOL_OK) {
+					return rc;
+				}
+				oprev = ocurr;
+				ocurr = ocurr->next;
+				ncurr = nmatch->next;
+				continue;
+			}
+			/* Handle gap in new: old = (A B C)  new = (A C) */
+			omatch = __cil_ordered_find_match(ncurr, ocurr->next);
+			if (omatch) {
+				/* Nothing to insert, just skip */
+				oprev = omatch;
+				ocurr = omatch->next;
+				ncurr = ncurr->next;
+				continue;
+			} else {
+				return SEPOL_ERR;
+			}
+		}
+	}
+
+	if (ncurr) {
+		/* Add the rest of the items from the new list */
+		rc = __cil_ordered_list_insert(old, old->tail, ncurr, NULL);
+		if (rc != SEPOL_OK) {
+			return rc;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+static int insert_unordered(struct cil_list *merged, struct cil_list *unordered)
+{
+	struct cil_list_item *curr = NULL;
+	struct cil_ordered_list *unordered_list = NULL;
+	struct cil_list_item *item = NULL;
+	struct cil_list_item *ret = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_list_for_each(curr, unordered) {
+		unordered_list = curr->data;
+
+		cil_list_for_each(item, unordered_list->list) {
+			if (cil_list_contains(merged, item->data)) {
+				/* item was declared in an ordered statement, which supercedes
+				 * all unordered statements */
+				if (item->flavor == CIL_CLASS) {
+					cil_log(CIL_WARN, "Ignoring '%s' as it has already been declared in classorder.\n", ((struct cil_class*)(item->data))->datum.name);
+				}
+				continue;
+			}
+
+			ret = __cil_ordered_item_insert(merged, merged->tail, item);
+			if (ret == NULL) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+struct cil_list *__cil_ordered_lists_merge_all(struct cil_list **ordered_lists, struct cil_list **unordered_lists)
+{
+	struct cil_list *composite = NULL;
+	struct cil_list_item *curr = NULL;
+	int changed = CIL_TRUE;
+	int waiting = 1;
+	int rc = SEPOL_ERR;
+
+	cil_list_init(&composite, CIL_LIST_ITEM);
+
+	while (waiting && changed == CIL_TRUE) {
+		changed = CIL_FALSE;
+		waiting = 0;
+		cil_list_for_each(curr, *ordered_lists) {
+			struct cil_ordered_list *ordered_list = curr->data;
+			if (ordered_list->merged == CIL_FALSE) {
+				rc = __cil_ordered_lists_merge(composite, ordered_list->list);
+				if (rc != SEPOL_OK) {
+					/* Can't merge yet */
+					waiting++;
+				} else {
+					ordered_list->merged = CIL_TRUE;
+					changed = CIL_TRUE;
+				}
+			}
+		}
+		if (waiting > 0 && changed == CIL_FALSE) {
+			cil_list_for_each(curr, *ordered_lists) {
+				struct cil_ordered_list *ordered_list = curr->data;
+				if (ordered_list->merged == CIL_FALSE) {
+					cil_tree_log(ordered_list->node, CIL_ERR, "Unable to merge ordered list");
+				}
+			}
+			goto exit;
+		}
+	}
+
+	if (unordered_lists != NULL) {
+		rc = insert_unordered(composite, *unordered_lists);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	__cil_ordered_lists_destroy(ordered_lists);
+	__cil_ordered_lists_destroy(unordered_lists);
+
+	return composite;
+
+exit:
+	__cil_ordered_lists_destroy(ordered_lists);
+	__cil_ordered_lists_destroy(unordered_lists);
+	cil_list_destroy(&composite, CIL_FALSE);
+	return NULL;
+}
+
+int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list *classorder_list = args->classorder_lists;
+	struct cil_list *unordered_classorder_list = args->unordered_classorder_lists;
+	struct cil_classorder *classorder = current->data;
+	struct cil_list *new = NULL;
+	struct cil_list_item *curr = NULL;
+	struct cil_symtab_datum *datum = NULL;
+	struct cil_ordered_list *class_list = NULL;
+	int rc = SEPOL_ERR;
+	int unordered = CIL_FALSE;
+
+	cil_list_init(&new, CIL_CLASSORDER);
+
+	cil_list_for_each(curr, classorder->class_list_str) {
+		if (curr->data == CIL_KEY_UNORDERED) {
+			unordered = CIL_TRUE;
+			continue;
+		}
+
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to resolve class %s in classorder\n", (char *)curr->data);
+			goto exit;
+		}
+		cil_list_append(new, CIL_CLASS, datum);
+	}
+
+	__cil_ordered_list_init(&class_list);
+	class_list->list = new;
+	class_list->node = current;
+	if (unordered) {
+		cil_list_append(unordered_classorder_list, CIL_CLASSORDER, class_list);
+	} else {
+		cil_list_append(classorder_list, CIL_CLASSORDER, class_list);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list *sidorder_list = args->sidorder_lists;
+	struct cil_sidorder *sidorder = current->data;
+	struct cil_list *new = NULL;
+	struct cil_list_item *curr = NULL;
+	struct cil_symtab_datum *datum = NULL;
+	struct cil_ordered_list *ordered = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_list_init(&new, CIL_SIDORDER);
+
+	cil_list_for_each(curr, sidorder->sid_list_str) {
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SIDS, extra_args, &datum);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to resolve sid %s in sidorder\n", (char *)curr->data);
+			goto exit;
+		}
+		cil_list_append(new, CIL_SID, datum);
+	}
+
+	__cil_ordered_list_init(&ordered);
+	ordered->list = new;
+	ordered->node = current;
+	cil_list_append(sidorder_list, CIL_SIDORDER, ordered);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+void cil_set_cat_values(struct cil_list *ordered_cats, struct cil_db *db)
+{
+	struct cil_list_item *curr;
+	int v = 0;
+
+	cil_list_for_each(curr, ordered_cats) {
+		struct cil_cat *cat = curr->data;
+		cat->value = v;
+		v++;
+	}
+
+	db->num_cats = v;
+}
+
+int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list *catorder_list = args->catorder_lists;
+	struct cil_catorder *catorder = current->data;
+	struct cil_list *new = NULL;
+	struct cil_list_item *curr = NULL;
+	struct cil_symtab_datum *cat_datum;
+	struct cil_cat *cat = NULL;
+	struct cil_ordered_list *ordered = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_list_init(&new, CIL_CATORDER);
+
+	cil_list_for_each(curr, catorder->cat_list_str) {
+		struct cil_tree_node *node = NULL;
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CATS, extra_args, &cat_datum);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to resolve category %s in categoryorder\n", (char *)curr->data);
+			goto exit;
+		}
+		node = cat_datum->nodes->head->data;
+		if (node->flavor != CIL_CAT) {
+			cil_log(CIL_ERR, "%s is not a category. Only categories are allowed in categoryorder statements\n", cat_datum->name);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		cat = (struct cil_cat *)cat_datum;
+		cil_list_append(new, CIL_CAT, cat);
+	}
+
+	__cil_ordered_list_init(&ordered);
+	ordered->list = new;
+	ordered->node = current;
+	cil_list_append(catorder_list, CIL_CATORDER, ordered);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list *sensitivityorder_list = args->sensitivityorder_lists;
+	struct cil_sensorder *sensorder = current->data;
+	struct cil_list *new = NULL;
+	struct cil_list_item *curr = NULL;
+	struct cil_symtab_datum *datum = NULL;
+	struct cil_ordered_list *ordered = NULL;
+	int rc = SEPOL_ERR;
+
+	cil_list_init(&new, CIL_LIST_ITEM);
+
+	cil_list_for_each(curr, sensorder->sens_list_str) {
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SENS, extra_args, &datum);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to resolve sensitivty %s in sensitivityorder\n", (char *)curr->data);
+			goto exit;
+		}
+		cil_list_append(new, CIL_SENS, datum);
+	}
+
+	__cil_ordered_list_init(&ordered);
+	ordered->list = new;
+	ordered->node = current;
+	cil_list_append(sensitivityorder_list, CIL_SENSITIVITYORDER, ordered);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_cats(struct cil_tree_node *current, struct cil_cats *cats, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_expr(CIL_CATSET, cats->str_expr, &cats->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_cats(current, catset->cats, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_verify_no_self_reference((struct cil_symtab_datum *)catset, catset->cats->datum_expr);
+	if (rc != SEPOL_OK) {
+		cil_list_destroy(&catset->cats->datum_expr, CIL_FALSE);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+int cil_resolve_senscat(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_senscat *senscat = current->data;
+	struct cil_symtab_datum *sens_datum;
+	struct cil_sens *sens = NULL;
+
+	rc = cil_resolve_name(current, (char*)senscat->sens_str, CIL_SYM_SENS, extra_args, &sens_datum);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to find sensitivity\n");
+		goto exit;
+	}
+
+	rc = cil_resolve_cats(current, senscat->cats, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	sens = (struct cil_sens *)sens_datum;
+
+	if (sens->cats_list == NULL ) {
+		cil_list_init(&sens->cats_list, CIL_CAT);
+	}
+
+	cil_list_append(sens->cats_list, CIL_CAT, senscat->cats);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_level(struct cil_tree_node *current, struct cil_level *level, void *extra_args)
+{
+	struct cil_symtab_datum *sens_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, (char*)level->sens_str, CIL_SYM_SENS, extra_args, &sens_datum);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Failed to find sensitivity\n");
+		goto exit;
+	}
+
+	level->sens = (struct cil_sens *)sens_datum;
+
+	if (level->cats != NULL) {
+		rc = cil_resolve_cats(current, level->cats, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_levelrange(struct cil_tree_node *current, struct cil_levelrange *lvlrange, void *extra_args)
+{
+	struct cil_symtab_datum *low_datum = NULL;
+	struct cil_symtab_datum *high_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (lvlrange->low_str != NULL) {
+		rc = cil_resolve_name(current, lvlrange->low_str, CIL_SYM_LEVELS, extra_args, &low_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		lvlrange->low = (struct cil_level*)low_datum;
+
+		/* This could still be an anonymous level even if low_str is set, if low_str is a param_str */
+		if (lvlrange->low->datum.name == NULL) {
+			rc = cil_resolve_level(current, lvlrange->low, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (lvlrange->low != NULL) {
+		rc = cil_resolve_level(current, lvlrange->low, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (lvlrange->high_str != NULL) {
+		rc = cil_resolve_name(current, lvlrange->high_str, CIL_SYM_LEVELS, extra_args, &high_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		lvlrange->high = (struct cil_level*)high_datum;
+
+		/* This could still be an anonymous level even if high_str is set, if high_str is a param_str */
+		if (lvlrange->high->datum.name == NULL) {
+			rc = cil_resolve_level(current, lvlrange->high, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (lvlrange->high != NULL) {
+		rc = cil_resolve_level(current, lvlrange->high, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_constrain(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_constrain *cons = current->data;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_classperms_list(current, cons->classperms, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_expr(CIL_CONSTRAIN, cons->str_expr, &cons->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_validatetrans *validtrans = current->data;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_symtab_datum *class_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, validtrans->class_str, CIL_SYM_CLASSES, args, &class_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	validtrans->class = (struct cil_class*)class_datum;
+
+	rc = cil_resolve_expr(CIL_VALIDATETRANS, validtrans->str_expr, &validtrans->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args)
+{
+	struct cil_symtab_datum *user_datum = NULL;
+	struct cil_symtab_datum *role_datum = NULL;
+	struct cil_symtab_datum *type_datum = NULL;
+	struct cil_tree_node *node = NULL;
+	struct cil_symtab_datum *lvlrange_datum = NULL;
+
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, context->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	node = user_datum->nodes->head->data;
+
+	if (node->flavor != CIL_USER) {
+		cil_log(CIL_ERR, "Context user must be a user: %s\n", user_datum->fqn);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	context->user = (struct cil_user*)user_datum;
+
+	rc = cil_resolve_name(current, context->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	node = role_datum->nodes->head->data;
+	if (node->flavor != CIL_ROLE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Context role not a role: %s\n", role_datum->fqn);
+		goto exit;
+	}
+
+	context->role = (struct cil_role*)role_datum;
+
+	rc = cil_resolve_name(current, context->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	node = type_datum->nodes->head->data;
+
+	if (node->flavor != CIL_TYPE && node->flavor != CIL_TYPEALIAS) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Type not a type or type alias\n");
+		goto exit;
+	}
+	context->type = type_datum;
+
+	if (context->range_str != NULL) {
+		rc = cil_resolve_name(current, context->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		context->range = (struct cil_levelrange*)lvlrange_datum;
+
+		/* This could still be an anonymous levelrange even if levelrange_str is set, if levelrange_str is a param_str*/
+		if (context->range->datum.name == NULL) {
+			rc = cil_resolve_levelrange(current, context->range, extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else if (context->range != NULL) {
+		rc = cil_resolve_levelrange(current, context->range, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_filecon *filecon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (filecon->context_str != NULL) {
+		rc = cil_resolve_name(current, filecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			return rc;
+		}
+		filecon->context = (struct cil_context*)context_datum;
+	} else if (filecon->context != NULL) {
+		rc = cil_resolve_context(current, filecon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			return rc;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_portcon *portcon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (portcon->context_str != NULL) {
+		rc = cil_resolve_name(current, portcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		portcon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, portcon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_genfscon *genfscon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (genfscon->context_str != NULL) {
+		rc = cil_resolve_name(current, genfscon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		genfscon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, genfscon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_nodecon *nodecon = current->data;
+	struct cil_symtab_datum *addr_datum = NULL;
+	struct cil_symtab_datum *mask_datum = NULL;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (nodecon->addr_str != NULL) {
+		rc = cil_resolve_name(current, nodecon->addr_str, CIL_SYM_IPADDRS, extra_args, &addr_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		nodecon->addr = (struct cil_ipaddr*)addr_datum;
+	}
+
+	if (nodecon->mask_str != NULL) {
+		rc = cil_resolve_name(current, nodecon->mask_str, CIL_SYM_IPADDRS, extra_args, &mask_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		nodecon->mask = (struct cil_ipaddr*)mask_datum;
+	}
+
+	if (nodecon->context_str != NULL) {
+		rc = cil_resolve_name(current, nodecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		nodecon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, nodecon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (nodecon->addr->family != nodecon->mask->family) {
+		cil_log(CIL_ERR, "Nodecon ip address not in the same family\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_netifcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_netifcon *netifcon = current->data;
+	struct cil_symtab_datum *ifcon_datum = NULL;
+	struct cil_symtab_datum *packcon_datum = NULL;
+
+	int rc = SEPOL_ERR;
+
+	if (netifcon->if_context_str != NULL) {
+		rc = cil_resolve_name(current, netifcon->if_context_str, CIL_SYM_CONTEXTS, extra_args, &ifcon_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		netifcon->if_context = (struct cil_context*)ifcon_datum;
+	} else {
+		rc = cil_resolve_context(current, netifcon->if_context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (netifcon->packet_context_str != NULL) {
+		rc = cil_resolve_name(current, netifcon->packet_context_str, CIL_SYM_CONTEXTS, extra_args, &packcon_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		netifcon->packet_context = (struct cil_context*)packcon_datum;
+	} else {
+		rc = cil_resolve_context(current, netifcon->packet_context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_pirqcon *pirqcon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (pirqcon->context_str != NULL) {
+		rc = cil_resolve_name(current, pirqcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		pirqcon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, pirqcon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_iomemcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_iomemcon *iomemcon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (iomemcon->context_str != NULL) {
+		rc = cil_resolve_name(current, iomemcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		iomemcon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, iomemcon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_ioportcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_ioportcon *ioportcon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (ioportcon->context_str != NULL) {
+		rc = cil_resolve_name(current, ioportcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		ioportcon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, ioportcon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_pcidevicecon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_pcidevicecon *pcidevicecon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (pcidevicecon->context_str != NULL) {
+		rc = cil_resolve_name(current, pcidevicecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		pcidevicecon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, pcidevicecon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_devicetreecon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_devicetreecon *devicetreecon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (devicetreecon->context_str != NULL) {
+		rc = cil_resolve_name(current, devicetreecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		devicetreecon->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, devicetreecon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_fsuse(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_fsuse *fsuse = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (fsuse->context_str != NULL) {
+		rc = cil_resolve_name(current, fsuse->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		fsuse->context = (struct cil_context*)context_datum;
+	} else {
+		rc = cil_resolve_context(current, fsuse->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_sidcontext(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_sidcontext *sidcon = current->data;
+	struct cil_symtab_datum *sid_datum = NULL;
+	struct cil_symtab_datum *context_datum = NULL;
+	struct cil_sid *sid = NULL;
+
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, sidcon->sid_str, CIL_SYM_SIDS, extra_args, &sid_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	sid = (struct cil_sid*)sid_datum;
+
+	if (sidcon->context_str != NULL) {
+		rc = cil_resolve_name(current, sidcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		sidcon->context = (struct cil_context*)context_datum;
+	} else if (sidcon->context != NULL) {
+		rc = cil_resolve_context(current, sidcon->context, extra_args);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	if (sid->context != NULL) {
+		cil_log(CIL_ERR, "sid's cannot be associated with more than one context\n");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	sid->context = sidcon->context;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_blockinherit *inherit = current->data;
+	struct cil_symtab_datum *block_datum = NULL;
+	struct cil_tree_node *node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	node = block_datum->nodes->head->data;
+
+	if (node->flavor != CIL_BLOCK) {
+		cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node));
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	inherit->block = (struct cil_block *)block_datum;
+
+	if (inherit->block->bi_nodes == NULL) {
+		cil_list_init(&inherit->block->bi_nodes, CIL_NODE);
+	}
+	cil_list_append(inherit->block->bi_nodes, CIL_NODE, current);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node)
+{
+	struct cil_list *trace = NULL;
+	struct cil_list_item *item = NULL;
+	struct cil_tree_node *curr = NULL;
+
+	cil_list_init(&trace, CIL_NODE);
+
+	for (curr = bi_node; curr != terminating_node; curr = curr->parent) {
+		if (curr->flavor == CIL_BLOCK) {
+			cil_list_prepend(trace, CIL_NODE, curr);
+		} else {
+			if (curr != bi_node) {
+				cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block));
+			}
+			cil_list_prepend(trace, CIL_NODE, curr);
+		}
+	}
+	cil_list_prepend(trace, CIL_NODE, terminating_node);
+
+	cil_list_for_each(item, trace) {
+		curr = item->data;
+		if (curr->flavor == CIL_BLOCK) {
+			cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name);
+		} else {
+			cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str);
+		}
+	}
+
+	cil_list_destroy(&trace, CIL_FALSE);
+}
+
+int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node)
+{
+	struct cil_tree_node *curr = NULL;
+	struct cil_blockinherit *bi = NULL;
+	struct cil_block *block = NULL;
+	int rc = SEPOL_ERR;
+
+	bi = bi_node->data;
+
+	for (curr = bi_node->parent; curr != NULL; curr = curr->parent) {
+		if (curr->flavor != CIL_BLOCK) {
+			continue;
+		}
+
+		block = curr->data;
+
+		if (block != bi->block) {
+			continue;
+		}
+
+		cil_log(CIL_ERR, "Recursive blockinherit found:\n");
+		cil_print_recursive_blockinherit(bi_node, curr);
+
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_block *block = current->data;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = NULL;
+	struct cil_list_item *item = NULL;
+	int rc = SEPOL_ERR;
+
+	// This block is not inherited
+	if (block->bi_nodes == NULL) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	db = args->db;
+
+	// Make sure this is the original block and not a merged block from a blockinherit
+	if (current != block->datum.nodes->head->data) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	cil_list_for_each(item, block->bi_nodes) {
+		rc = cil_check_recursive_blockinherit(item->data);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_copy_ast(db, current, item->data);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n");
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_blockabstract *abstract = current->data;
+	struct cil_symtab_datum *block_datum = NULL;
+	struct cil_tree_node *block_node = NULL;
+	int rc = SEPOL_ERR;
+
+	rc = cil_resolve_name(current, abstract->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	block_node = block_datum->nodes->head->data;
+	if (block_node->flavor != CIL_BLOCK) {
+		cil_log(CIL_ERR, "Failed to resolve blockabstract to a block, rc: %d\n", rc);
+		goto exit;
+	}
+
+	((struct cil_block*)block_datum)->is_abstract = CIL_TRUE;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_in(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_in *in = current->data;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = NULL;
+	struct cil_symtab_datum *block_datum = NULL;
+	struct cil_tree_node *block_node = NULL;
+	int rc = SEPOL_ERR;
+
+	if (args != NULL) {
+		db = args->db;
+	}
+
+	rc = cil_resolve_name(current, in->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	block_node = block_datum->nodes->head->data;
+
+	rc = cil_copy_ast(db, current, block_node);
+	if (rc != SEPOL_OK) {
+		printf("Failed to copy in, rc: %d\n", rc);
+		goto exit;
+	}
+
+	cil_tree_children_destroy(current);
+	current->cl_head = NULL;
+	current->cl_tail = NULL;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_in_list(void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_list *ins = args->in_list;
+	struct cil_list_item *curr = NULL;
+	struct cil_tree_node *node = NULL;
+	struct cil_tree_node *last_failed_node = NULL;
+	struct cil_in *in = NULL;
+	struct cil_symtab_datum *block_datum = NULL;
+	int resolved = 0;
+	int unresolved = 0;
+	int rc = SEPOL_ERR;
+
+	do {
+		resolved = 0;
+		unresolved = 0;
+
+		cil_list_for_each(curr, ins) {
+			if (curr->flavor != CIL_NODE) {
+				continue;
+			}
+
+			node = curr->data;
+			in = node->data;
+
+			rc = cil_resolve_name(node, in->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+			if (rc != SEPOL_OK) {
+				unresolved++;
+				last_failed_node = node;
+			} else {
+				rc = cil_resolve_in(node, extra_args);
+				if (rc != SEPOL_OK) {
+					goto exit;
+				}
+				
+				resolved++;
+				curr->data = NULL;
+				curr->flavor = CIL_NONE;
+			}
+		}
+
+		if (unresolved > 0 && resolved == 0) {
+			cil_tree_log(last_failed_node, CIL_ERR, "Failed to resolve in-statement");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+	} while (unresolved > 0);
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+
+int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor)
+{
+	int rc = SEPOL_ERR;
+	struct cil_bounds *bounds = current->data;
+	enum cil_sym_index index;
+	struct cil_symtab_datum *parent_datum = NULL;
+	struct cil_symtab_datum *child_datum = NULL;
+
+	rc = cil_flavor_to_symtab_index(flavor, &index);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_name(current, bounds->parent_str, index, extra_args, &parent_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_resolve_name(current, bounds->child_str, index, extra_args, &child_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	switch (flavor) {
+	case CIL_USER: {
+		struct cil_user *user = (struct cil_user *)child_datum;
+
+		if (user->bounds != NULL) {
+			struct cil_tree_node *node = user->bounds->datum.nodes->head->data;
+			cil_tree_log(node, CIL_ERR, "User %s already bound by parent", bounds->child_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		user->bounds = (struct cil_user *)parent_datum;
+		break;
+	}
+	case CIL_ROLE: {
+		struct cil_role *role = (struct cil_role *)child_datum;
+
+		if (role->bounds != NULL) {
+			struct cil_tree_node *node = role->bounds->datum.nodes->head->data;
+			cil_tree_log(node, CIL_ERR, "Role %s already bound by parent", bounds->child_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		role->bounds = (struct cil_role *)parent_datum;
+		break;
+	}
+	case CIL_TYPE: {
+		struct cil_type *type = (struct cil_type *)child_datum;
+		struct cil_tree_node *node = NULL;
+
+		if (type->bounds != NULL) {
+			node = ((struct cil_symtab_datum *)type->bounds)->nodes->head->data;
+			cil_tree_log(node, CIL_ERR, "Type %s already bound by parent", bounds->child_str);
+			cil_tree_log(current, CIL_ERR, "Now being bound to parent %s", bounds->parent_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		node = parent_datum->nodes->head->data;
+		if (node->flavor == CIL_TYPEATTRIBUTE) {
+			cil_log(CIL_ERR, "Bounds parent %s is an attribute\n", bounds->parent_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		node = child_datum->nodes->head->data;
+		if (node->flavor == CIL_TYPEATTRIBUTE) {
+			cil_log(CIL_ERR, "Bounds child %s is an attribute\n", bounds->child_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		type->bounds = (struct cil_type *)parent_datum;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(current, CIL_ERR, "Bad bounds statement");
+	return rc;
+}
+
+int cil_resolve_default(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_default *def = current->data;
+	struct cil_list_item *curr;
+	struct cil_symtab_datum *datum;
+
+	cil_list_init(&def->class_datums, def->flavor);
+
+	cil_list_for_each(curr, def->class_strs) {
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_append(def->class_datums, CIL_CLASS, datum);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_defaultrange(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_defaultrange *def = current->data;
+	struct cil_list_item *curr;
+	struct cil_symtab_datum *datum;
+
+	cil_list_init(&def->class_datums, CIL_DEFAULTRANGE);
+
+	cil_list_for_each(curr, def->class_strs) {
+		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cil_list_append(def->class_datums, CIL_CLASS, datum);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *terminating_node)
+{
+	struct cil_list *trace = NULL;
+	struct cil_list_item * item = NULL;
+	struct cil_tree_node *curr = NULL;
+
+	cil_list_init(&trace, CIL_NODE);
+
+	for (curr = call_node; curr != terminating_node; curr = curr->parent) {
+		if (curr->flavor == CIL_CALL) {
+			if (curr != call_node) {
+				cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)curr->data)->macro));
+			}
+			cil_list_prepend(trace, CIL_NODE, curr);
+		}
+	}
+
+	if (terminating_node->flavor == CIL_MACRO) {
+		cil_list_prepend(trace, CIL_NODE, terminating_node);
+	} else {
+		cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)terminating_node->data)->macro));
+	}
+
+	cil_list_for_each(item, trace) {
+		curr = item->data;
+		if (curr->flavor == CIL_MACRO) {
+			cil_tree_log(curr, CIL_ERR, "macro %s", DATUM(curr->data)->name);
+		} else {
+			cil_tree_log(curr, CIL_ERR, "call %s", ((struct cil_call *)curr->data)->macro_str);
+		}
+	}
+
+	cil_list_destroy(&trace, CIL_FALSE);
+}
+
+int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node)
+{
+	struct cil_tree_node *curr = NULL;
+	struct cil_call * call = NULL;
+	int rc = SEPOL_ERR;
+
+	for (curr = call_node; curr != NULL; curr = curr->parent) {
+		if (curr->flavor == CIL_CALL) {
+			if (curr == call_node) {
+				continue;
+			}
+
+			call = curr->data;
+			if (call->macro != macro_node->data) {
+				continue;
+			}
+		} else if (curr->flavor == CIL_MACRO) {
+			if (curr != macro_node) {
+				rc = SEPOL_OK;
+				goto exit;
+			}
+		} else {
+			continue;
+		}
+
+		cil_log(CIL_ERR, "Recursive macro call found:\n");
+		cil_print_recursive_call(call_node, curr);
+
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
+int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_call *new_call = current->data;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = NULL;
+	struct cil_tree_node *macro_node = NULL;
+	struct cil_symtab_datum *macro_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (args != NULL) {
+		db = args->db;
+	}
+
+	rc = cil_resolve_name(current, new_call->macro_str, CIL_SYM_BLOCKS, extra_args, &macro_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	macro_node = macro_datum->nodes->head->data;
+
+	if (macro_node->flavor != CIL_MACRO) {
+		printf("Failed to resolve %s to a macro\n", new_call->macro_str);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+	new_call->macro = (struct cil_macro*)macro_datum;
+
+	if (new_call->macro->params != NULL ) {
+
+		struct cil_list_item *item;
+		struct cil_args *new_arg = NULL;
+		struct cil_tree_node *pc = NULL;
+
+		if (new_call->args_tree == NULL) {
+			cil_tree_log(current, CIL_ERR, "Missing arguments");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		pc = new_call->args_tree->root->cl_head;
+
+		cil_list_init(&new_call->args, CIL_LIST_ITEM);
+
+		cil_list_for_each(item, new_call->macro->params) {
+			enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor;
+
+			if (pc == NULL) {
+				cil_tree_log(current, CIL_ERR, "Missing arguments");
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			if (item->flavor != CIL_PARAM) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+
+			cil_args_init(&new_arg);
+
+			switch (flavor) {
+			case CIL_NAME: {
+				struct cil_name *name;
+				name = __cil_insert_name(args->db, pc->data, current);
+				if (name != NULL) {
+					new_arg->arg = (struct cil_symtab_datum *)name;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+			}
+				break;
+			case CIL_TYPE:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_ROLE:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_USER:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_SENS:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_CAT:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_BOOL:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_CATSET: {
+				if (pc->cl_head != NULL) {
+					struct cil_catset *catset = NULL;
+					struct cil_tree_node *cat_node = NULL;
+					cil_catset_init(&catset);
+					rc = cil_fill_cats(pc, &catset->cats);
+					if (rc != SEPOL_OK) {
+						cil_destroy_catset(catset);
+						goto exit;
+					}
+					cil_tree_node_init(&cat_node);
+					cat_node->flavor = CIL_CATSET;
+					cat_node->data = catset;
+					cil_list_append(((struct cil_symtab_datum*)catset)->nodes,
+									CIL_LIST_ITEM, cat_node);
+					new_arg->arg = (struct cil_symtab_datum*)catset;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+
+				break;
+			}
+			case CIL_LEVEL: {
+				if (pc->cl_head != NULL) {
+					struct cil_level *level = NULL;
+					struct cil_tree_node *lvl_node = NULL;
+					cil_level_init(&level);
+
+					rc = cil_fill_level(pc->cl_head, level);
+					if (rc != SEPOL_OK) {
+						cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc);
+						cil_destroy_level(level);
+						goto exit;
+					}
+					cil_tree_node_init(&lvl_node);
+					lvl_node->flavor = CIL_LEVEL;
+					lvl_node->data = level;
+					cil_list_append(((struct cil_symtab_datum*)level)->nodes, 
+									CIL_LIST_ITEM, lvl_node);
+					new_arg->arg = (struct cil_symtab_datum*)level;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+
+				break;
+			}
+			case CIL_LEVELRANGE: {
+				if (pc->cl_head != NULL) {
+					struct cil_levelrange *range = NULL;
+					struct cil_tree_node *range_node = NULL;
+					cil_levelrange_init(&range);
+
+					rc = cil_fill_levelrange(pc->cl_head, range);
+					if (rc != SEPOL_OK) {
+						cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc);
+						cil_destroy_levelrange(range);
+						goto exit;
+					}
+					cil_tree_node_init(&range_node);
+					range_node->flavor = CIL_LEVELRANGE;
+					range_node->data = range;
+					cil_list_append(((struct cil_symtab_datum*)range)->nodes, 
+									CIL_LIST_ITEM, range_node);
+					new_arg->arg = (struct cil_symtab_datum*)range;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+
+				break;
+			}
+			case CIL_IPADDR: {
+				if (pc->cl_head != NULL) {
+					struct cil_ipaddr *ipaddr = NULL;
+					struct cil_tree_node *addr_node = NULL;
+					cil_ipaddr_init(&ipaddr);
+
+					rc = cil_fill_ipaddr(pc->cl_head, ipaddr);
+					if (rc != SEPOL_OK) {
+						cil_log(CIL_ERR, "Failed to create anonymous ip address, rc; %d\n", rc);
+						cil_destroy_ipaddr(ipaddr);
+						goto exit;
+					}
+					cil_tree_node_init(&addr_node);
+					addr_node->flavor = CIL_IPADDR;
+					addr_node->data = ipaddr;
+					cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes,
+									CIL_LIST_ITEM, addr_node);
+					new_arg->arg = (struct cil_symtab_datum*)ipaddr;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+
+				break;
+			}
+			case CIL_CLASS:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_MAP_CLASS:
+				new_arg->arg_str = pc->data;
+				break;
+			case CIL_CLASSPERMISSION: {
+				if (pc->cl_head != NULL) {
+					struct cil_classpermission *cp = NULL;
+					struct cil_tree_node *cp_node = NULL;
+
+					cil_classpermission_init(&cp);
+					rc = cil_fill_classperms_list(pc, &cp->classperms);
+					if (rc != SEPOL_OK) {
+						cil_log(CIL_ERR, "Failed to create anonymous classpermission\n");
+						cil_destroy_classpermission(cp);
+						goto exit;
+					}
+					cil_tree_node_init(&cp_node);
+					cp_node->flavor = CIL_CLASSPERMISSION;
+					cp_node->data = cp;
+					cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node);
+					new_arg->arg = (struct cil_symtab_datum*)cp;
+				} else {
+					new_arg->arg_str = pc->data;
+				}
+				break;
+			}
+			default:
+				cil_log(CIL_ERR, "Unexpected flavor: %d\n", 
+						(((struct cil_param*)item->data)->flavor));
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			new_arg->param_str = ((struct cil_param*)item->data)->str;
+			new_arg->flavor = flavor;
+
+			cil_list_append(new_call->args, CIL_ARGS, new_arg);
+
+			pc = pc->next;
+		}
+
+		if (pc != NULL) {
+			cil_tree_log(current, CIL_ERR, "Unexpected arguments");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else if (new_call->args_tree != NULL) {
+		cil_tree_log(current, CIL_ERR, "Unexpected arguments");
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (new_call->copied == 0) {
+		new_call->copied = 1;
+
+		rc = cil_check_recursive_call(current, macro_node);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		rc = cil_copy_ast(db, macro_node, current);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_call2(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_call *new_call = current->data;
+	int rc = SEPOL_ERR;
+	enum cil_sym_index sym_index = CIL_SYM_UNKNOWN;
+	struct cil_list_item *item;
+
+	if (new_call->args == NULL) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	cil_list_for_each(item, new_call->args) {
+		struct cil_args *arg = item->data;
+		if (arg->arg == NULL && arg->arg_str == NULL) {
+			cil_log(CIL_ERR, "Arguments not created correctly\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		switch (arg->flavor) {
+		case CIL_NAME:
+			if (arg->arg != NULL) {
+				continue; /* No need to resolve */
+			} else {
+				sym_index = CIL_SYM_NAMES;
+			}
+			break;
+		case CIL_LEVEL:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue; // anonymous, no need to resolve
+			} else {
+				sym_index = CIL_SYM_LEVELS;
+			}
+			break;
+		case CIL_LEVELRANGE:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue; // anonymous, no need to resolve
+			} else {
+				sym_index = CIL_SYM_LEVELRANGES;
+			}
+			break;
+		case CIL_CATSET:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue; // anonymous, no need to resolve
+			} else {
+				sym_index = CIL_SYM_CATS;
+			}
+			break;
+		case CIL_IPADDR:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue; // anonymous, no need to resolve
+			} else {
+				sym_index = CIL_SYM_IPADDRS;
+			}
+			break;
+		case CIL_CLASSPERMISSION:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue;
+			} else {
+				sym_index = CIL_SYM_CLASSPERMSETS;
+			}
+			break;
+		case CIL_TYPE:
+			if (arg->arg_str == NULL && arg->arg != NULL) {
+				continue; // anonymous, no need to resolve
+			} else {
+				sym_index = CIL_SYM_TYPES;
+			}
+			break;
+		case CIL_ROLE:
+			sym_index = CIL_SYM_ROLES;
+			break;
+		case CIL_USER:
+			sym_index = CIL_SYM_USERS;
+			break;
+		case CIL_SENS:
+			sym_index = CIL_SYM_SENS;
+			break;
+		case CIL_CAT:
+			sym_index = CIL_SYM_CATS;
+			break;
+		case CIL_CLASS:
+		case CIL_MAP_CLASS:
+			sym_index = CIL_SYM_CLASSES;
+			break;
+		case CIL_BOOL:
+			sym_index = CIL_SYM_BOOLS;
+			break;
+		default:
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		if (sym_index != CIL_SYM_UNKNOWN) {
+			rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &(arg->arg));
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_name_call_args(struct cil_call *call, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+	struct cil_list_item *item;
+	enum cil_sym_index param_index = CIL_SYM_UNKNOWN;
+	int rc = SEPOL_ERR;
+
+	if (call == NULL || name == NULL) {
+		goto exit;
+	}
+
+	if (call->args == NULL) {
+		goto exit;
+	}
+
+	cil_list_for_each(item, call->args) {
+		struct cil_args * arg = item->data;
+		rc = cil_flavor_to_symtab_index(arg->flavor, &param_index);
+		if (param_index == sym_index) {
+			if (name == arg->param_str) {
+				*datum = arg->arg;
+				rc = SEPOL_OK;
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_ERR;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struct cil_list **datum_expr, struct cil_tree_node *parent, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	struct cil_symtab_datum *res_datum = NULL;
+	enum cil_sym_index sym_index =  CIL_SYM_UNKNOWN;
+
+	switch (str_expr->flavor) {
+	case CIL_BOOL:
+		sym_index = CIL_SYM_BOOLS;
+		break;
+	case CIL_TUNABLE:
+		sym_index = CIL_SYM_TUNABLES;
+		break;
+	case CIL_TYPE:
+		sym_index = CIL_SYM_TYPES;
+		break;
+	case CIL_ROLE:
+		sym_index = CIL_SYM_ROLES;
+		break;
+	case CIL_USER:
+		sym_index = CIL_SYM_USERS;
+		break;
+	case CIL_CAT:
+		sym_index = CIL_SYM_CATS;
+		break;
+	default:
+		break;
+	}
+
+	cil_list_init(datum_expr, str_expr->flavor);
+
+	cil_list_for_each(curr, str_expr) {
+		switch (curr->flavor) {
+		case CIL_STRING:
+			rc = cil_resolve_name(parent, curr->data, sym_index, extra_args, &res_datum);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+
+			if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) {
+				cil_type_used(res_datum);
+			}
+
+			cil_list_append(*datum_expr, CIL_DATUM, res_datum);
+			break;
+		case CIL_LIST: {
+			struct cil_list *datum_sub_expr;
+			rc = cil_resolve_expr(expr_type, curr->data, &datum_sub_expr, parent, extra_args);
+			if (rc != SEPOL_OK) {
+				cil_list_destroy(&datum_sub_expr, CIL_TRUE);
+				goto exit;
+			}
+			cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr);
+			break;
+		}
+		default:
+			cil_list_append(*datum_expr, curr->flavor, curr->data);
+			break;
+		}				
+	}
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_booleanif *bif = (struct cil_booleanif*)current->data;
+
+	rc = cil_resolve_expr(CIL_BOOLEANIF, bif->str_expr, &bif->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_evaluate_tunable_expr(struct cil_list_item *curr);
+
+static int __cil_evaluate_tunable_expr_helper(struct cil_list_item *curr)
+{
+	if (curr == NULL) {
+		return CIL_FALSE;
+	} else if (curr->flavor == CIL_DATUM) {
+		struct cil_tunable *tun = curr->data;
+		return tun->value;
+	} else if (curr->flavor == CIL_LIST) {
+		struct cil_list *l = curr->data;
+		return __cil_evaluate_tunable_expr(l->head);
+	} else {
+		return CIL_FALSE;
+	}
+}
+
+static int __cil_evaluate_tunable_expr(struct cil_list_item *curr)
+{
+	/* Assumes expression is well-formed */
+
+	if (curr == NULL) {
+		return CIL_FALSE;
+	} else if (curr->flavor == CIL_OP) {
+		uint16_t v1, v2;
+		enum cil_flavor op_flavor = (enum cil_flavor)curr->data;
+
+		v1 = __cil_evaluate_tunable_expr_helper(curr->next);
+
+		if (op_flavor == CIL_NOT) return !v1;
+
+		v2 = __cil_evaluate_tunable_expr_helper(curr->next->next);
+
+		if (op_flavor == CIL_AND) return (v1 && v2);
+		else if (op_flavor == CIL_OR) return (v1 || v2);
+		else if (op_flavor == CIL_XOR) return (v1 ^ v2);
+		else if (op_flavor == CIL_EQ) return (v1 == v2);
+		else if (op_flavor == CIL_NEQ) return (v1 != v2);
+		else return CIL_FALSE;
+	} else {
+		uint16_t v;
+		for (;curr; curr = curr->next) {
+			v = __cil_evaluate_tunable_expr_helper(curr);
+			if (v) return v;
+		}
+		return CIL_FALSE;
+	}
+}
+
+int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = NULL;
+	int rc = SEPOL_ERR;
+	struct cil_tunableif *tif = (struct cil_tunableif*)current->data;
+	uint16_t result = CIL_FALSE;
+	struct cil_tree_node *true_node = NULL;
+	struct cil_tree_node *false_node = NULL;
+	struct cil_condblock *cb = NULL;
+
+	if (args != NULL) {
+		db = args->db;
+	}
+
+	rc = cil_resolve_expr(CIL_TUNABLEIF, tif->str_expr, &tif->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	result = __cil_evaluate_tunable_expr(tif->datum_expr->head);
+
+	if (current->cl_head != NULL && current->cl_head->flavor == CIL_CONDBLOCK) {
+		cb = current->cl_head->data;
+		if (cb->flavor == CIL_CONDTRUE) {
+			true_node = current->cl_head;
+		} else if (cb->flavor == CIL_CONDFALSE) {
+			false_node = current->cl_head;
+		}
+	}
+
+	if (current->cl_head != NULL && current->cl_head->next != NULL && current->cl_head->next->flavor == CIL_CONDBLOCK) {
+		cb = current->cl_head->next->data;
+		if (cb->flavor == CIL_CONDTRUE) {
+			true_node = current->cl_head->next;
+		} else if (cb->flavor == CIL_CONDFALSE) {
+			false_node = current->cl_head->next;
+		}
+	}
+
+	if (result == CIL_TRUE) {
+		if (true_node != NULL) {
+			rc = cil_copy_ast(db, true_node, current->parent);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	} else {
+		if (false_node != NULL) {
+			rc = cil_copy_ast(db, false_node, current->parent);
+			if (rc  != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	cil_tree_children_destroy(current);
+	current->cl_head = NULL;
+	current->cl_tail = NULL;
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_userattributeset *attrusers = current->data;
+	struct cil_symtab_datum *attr_datum = NULL;
+	struct cil_tree_node *attr_node = NULL;
+	struct cil_userattribute *attr = NULL;
+
+	rc = cil_resolve_name(current, attrusers->attr_str, CIL_SYM_USERS, extra_args, &attr_datum);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+	attr_node = attr_datum->nodes->head->data;
+
+	if (attr_node->flavor != CIL_USERATTRIBUTE) {
+		rc = SEPOL_ERR;
+		cil_log(CIL_ERR, "Attribute user not an attribute\n");
+		goto exit;
+	}
+	attr = (struct cil_userattribute*)attr_datum;
+
+	rc = cil_resolve_expr(CIL_USERATTRIBUTESET, attrusers->str_expr, &attrusers->datum_expr, current, extra_args);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = cil_verify_no_self_reference(attr_datum, attrusers->datum_expr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	if (attr->expr_list == NULL) {
+		cil_list_init(&attr->expr_list, CIL_USERATTRIBUTE);
+	}
+
+	cil_list_append(attr->expr_list, CIL_LIST, attrusers->datum_expr);
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
+{
+	int rc = SEPOL_OK;
+	struct cil_args_resolve *args = extra_args;
+	enum cil_pass pass = 0;
+	struct cil_list *ins = args->in_list;
+
+	if (node == NULL || args == NULL) {
+		goto exit;
+	}
+
+	pass = args->pass;
+	switch (pass) {
+	case CIL_PASS_TIF:
+		if (node->flavor == CIL_TUNABLEIF) {
+			rc = cil_resolve_tunif(node, args);
+		}
+		break;
+	case CIL_PASS_IN:
+		if (node->flavor == CIL_IN) {
+			// due to ordering issues, in statements are just gathered here and
+			// resolved together in cil_resolve_in_list once all are found
+			cil_list_prepend(ins, CIL_NODE, node);
+		}
+		break;
+	case CIL_PASS_BLKIN_LINK:
+		if (node->flavor == CIL_BLOCKINHERIT) {
+			rc = cil_resolve_blockinherit_link(node, args);
+		}
+		break;
+	case CIL_PASS_BLKIN_COPY:
+		if (node->flavor == CIL_BLOCK) {
+			rc = cil_resolve_blockinherit_copy(node, args);
+		}
+		break;
+	case CIL_PASS_BLKABS:
+		if (node->flavor == CIL_BLOCKABSTRACT) {
+			rc = cil_resolve_blockabstract(node, args);
+		}
+		break;
+	case CIL_PASS_MACRO:
+		if (node->flavor == CIL_CALL && args->macro != NULL) {
+			rc = cil_resolve_call1(node, args);
+		}
+		break;
+	case CIL_PASS_CALL1:
+		if (node->flavor == CIL_CALL) {
+			rc = cil_resolve_call1(node, args);
+		}
+		break;
+	case CIL_PASS_CALL2:
+		if (node->flavor == CIL_CALL) {
+			rc = cil_resolve_call2(node, args);
+		}
+		break;
+	case CIL_PASS_ALIAS1:
+		switch (node->flavor) {
+		case CIL_TYPEALIASACTUAL:
+			rc = cil_resolve_aliasactual(node, args, CIL_TYPE);
+			break;
+		case CIL_SENSALIASACTUAL:
+			rc = cil_resolve_aliasactual(node, args, CIL_SENS);
+			break;
+		case CIL_CATALIASACTUAL:
+			rc = cil_resolve_aliasactual(node, args, CIL_CAT);
+			break;
+		default: 
+			break;
+		}
+		break;
+	case CIL_PASS_ALIAS2:
+		switch (node->flavor) {
+		case CIL_TYPEALIAS:
+			rc = cil_resolve_alias_to_actual(node, CIL_TYPE);
+			break;
+		case CIL_SENSALIAS:
+			rc = cil_resolve_alias_to_actual(node, CIL_SENS);
+			break;
+		case CIL_CATALIAS:
+			rc = cil_resolve_alias_to_actual(node, CIL_CAT);
+			break;
+		default:
+			break;
+		}
+		break;
+	case CIL_PASS_MISC1:
+		switch (node->flavor) {
+		case CIL_SIDORDER:
+			rc = cil_resolve_sidorder(node, args);
+			break;
+		case CIL_CLASSORDER:
+			rc = cil_resolve_classorder(node, args);
+			break;
+		case CIL_CATORDER:
+			rc = cil_resolve_catorder(node, args);
+			break;
+		case CIL_SENSITIVITYORDER:
+			rc = cil_resolve_sensitivityorder(node, args);
+			break;
+		case CIL_BOOLEANIF:
+			rc = cil_resolve_boolif(node, args);
+			break;
+		default:
+			break;
+		}
+		break;
+	case CIL_PASS_MLS:
+		switch (node->flavor) {
+		case CIL_CATSET:
+			rc = cil_resolve_catset(node, (struct cil_catset*)node->data, args);
+			break;
+		default:
+			break;
+		}
+		break;
+	case CIL_PASS_MISC2:
+		switch (node->flavor) {
+		case CIL_SENSCAT:
+			rc = cil_resolve_senscat(node, args);
+			break;
+		case CIL_CLASSCOMMON:
+			rc = cil_resolve_classcommon(node, args);
+			break;
+		default:
+			break;
+		}
+		break;
+	case CIL_PASS_MISC3:
+		switch (node->flavor) {
+		case CIL_TYPEATTRIBUTESET:
+			rc = cil_resolve_typeattributeset(node, args);
+			break;
+		case CIL_TYPEBOUNDS:
+			rc = cil_resolve_bounds(node, args, CIL_TYPE);
+			break;
+		case CIL_TYPEPERMISSIVE:
+			rc = cil_resolve_typepermissive(node, args);
+			break;
+		case CIL_NAMETYPETRANSITION:
+			rc = cil_resolve_nametypetransition(node, args);
+			break;
+		case CIL_RANGETRANSITION:
+			rc = cil_resolve_rangetransition(node, args);
+			break;
+		case CIL_CLASSPERMISSIONSET:
+			rc = cil_resolve_classpermissionset(node, (struct cil_classpermissionset*)node->data, args);
+			break;
+		case CIL_CLASSMAPPING:
+			rc = cil_resolve_classmapping(node, args);
+			break;
+		case CIL_AVRULE:
+		case CIL_AVRULEX:
+			rc = cil_resolve_avrule(node, args);
+			break;
+		case CIL_PERMISSIONX:
+			rc = cil_resolve_permissionx(node, (struct cil_permissionx*)node->data, args);
+			break;
+		case CIL_TYPE_RULE:
+			rc = cil_resolve_type_rule(node, args);
+			break;
+		case CIL_USERROLE:
+			rc = cil_resolve_userrole(node, args);
+			break;
+		case CIL_USERLEVEL:
+			rc = cil_resolve_userlevel(node, args);
+			break;
+		case CIL_USERRANGE:
+			rc = cil_resolve_userrange(node, args);
+			break;
+		case CIL_USERBOUNDS:
+			rc = cil_resolve_bounds(node, args, CIL_USER);
+			break;
+		case CIL_USERPREFIX:
+			rc = cil_resolve_userprefix(node, args);
+			break;
+		case CIL_SELINUXUSER:
+		case CIL_SELINUXUSERDEFAULT:
+			rc = cil_resolve_selinuxuser(node, args);
+			break;
+		case CIL_ROLEATTRIBUTESET:
+			rc = cil_resolve_roleattributeset(node, args);
+			break;
+		case CIL_ROLETYPE:
+			rc = cil_resolve_roletype(node, args);
+			break;
+		case CIL_ROLETRANSITION:
+			rc = cil_resolve_roletransition(node, args);
+			break;
+		case CIL_ROLEALLOW:
+			rc = cil_resolve_roleallow(node, args);
+			break;
+		case CIL_ROLEBOUNDS:
+			rc = cil_resolve_bounds(node, args, CIL_ROLE);
+			break;
+		case CIL_LEVEL:
+			rc = cil_resolve_level(node, (struct cil_level*)node->data, args);
+			break;
+		case CIL_LEVELRANGE:
+			rc = cil_resolve_levelrange(node, (struct cil_levelrange*)node->data, args);
+			break;
+		case CIL_CONSTRAIN:
+			rc = cil_resolve_constrain(node, args);
+			break;
+		case CIL_MLSCONSTRAIN:
+			rc = cil_resolve_constrain(node, args);
+			break;
+		case CIL_VALIDATETRANS:
+		case CIL_MLSVALIDATETRANS:
+			rc = cil_resolve_validatetrans(node, args);
+			break;
+		case CIL_CONTEXT:
+			rc = cil_resolve_context(node, (struct cil_context*)node->data, args);
+			break;
+		case CIL_FILECON:
+			rc = cil_resolve_filecon(node, args);
+			break;
+		case CIL_PORTCON:
+			rc = cil_resolve_portcon(node, args);
+			break;
+		case CIL_NODECON:
+			rc = cil_resolve_nodecon(node, args);
+			break;
+		case CIL_GENFSCON:
+			rc = cil_resolve_genfscon(node, args);
+			break;
+		case CIL_NETIFCON:
+			rc = cil_resolve_netifcon(node, args);
+			break;
+		case CIL_PIRQCON:
+			rc = cil_resolve_pirqcon(node, args);
+			break;
+		case CIL_IOMEMCON:
+			rc = cil_resolve_iomemcon(node, args);
+			break;
+		case CIL_IOPORTCON:
+			rc = cil_resolve_ioportcon(node, args);
+			break;
+		case CIL_PCIDEVICECON:
+			rc = cil_resolve_pcidevicecon(node, args);
+			break;
+		case CIL_DEVICETREECON:
+			rc = cil_resolve_devicetreecon(node, args);
+			break;
+		case CIL_FSUSE:
+			rc = cil_resolve_fsuse(node, args);
+			break;
+		case CIL_SIDCONTEXT:
+			rc = cil_resolve_sidcontext(node, args);
+			break;
+		case CIL_DEFAULTUSER:
+		case CIL_DEFAULTROLE:
+		case CIL_DEFAULTTYPE:
+			rc = cil_resolve_default(node, args);
+			break;
+		case CIL_DEFAULTRANGE:
+			rc = cil_resolve_defaultrange(node, args);
+			break;
+		case CIL_USERATTRIBUTESET:
+			rc = cil_resolve_userattributeset(node, args);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+
+exit:
+	return rc;
+}
+
+int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve *args = extra_args;
+	enum cil_pass pass = args->pass;
+	struct cil_tree_node *optstack = args->optstack;
+	struct cil_tree_node *boolif = args->boolif;
+	struct cil_tree_node *blockstack = args->blockstack;
+	struct cil_tree_node *macro = args->macro;
+
+	if (node == NULL) {
+		goto exit;
+	}
+
+	if (optstack != NULL) {
+		if (node->flavor == CIL_TUNABLE || node->flavor == CIL_MACRO) {
+			/* tuanbles and macros are not allowed in optionals*/
+			cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node));
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	if (blockstack != NULL) {
+		if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) {
+			cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node));
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	if (macro != NULL) {
+		if (node->flavor == CIL_BLOCKINHERIT ||
+			node->flavor == CIL_BLOCK ||
+			node->flavor == CIL_BLOCKABSTRACT ||
+			node->flavor == CIL_MACRO) {
+			cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node));
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	if (boolif != NULL) {
+		if (!(node->flavor == CIL_CONDBLOCK ||
+			node->flavor == CIL_AVRULE ||
+			node->flavor == CIL_TYPE_RULE ||
+			node->flavor == CIL_CALL ||
+			node->flavor == CIL_TUNABLEIF ||
+			node->flavor == CIL_NAMETYPETRANSITION)) {
+			if (((struct cil_booleanif*)boolif->data)->preserved_tunable) {
+				cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node));
+			} else {
+				cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node));
+			}
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	if (node->flavor == CIL_MACRO) {
+		if (pass != CIL_PASS_TIF && pass != CIL_PASS_MACRO) {
+			*finished = CIL_TREE_SKIP_HEAD;
+			rc = SEPOL_OK;
+			goto exit;
+		}
+	}
+
+	if (node->flavor == CIL_BLOCK && ((((struct cil_block*)node->data)->is_abstract == CIL_TRUE) && (pass > CIL_PASS_BLKABS))) {
+		*finished = CIL_TREE_SKIP_HEAD;
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	rc = __cil_resolve_ast_node(node, extra_args);
+	if (rc == SEPOL_ENOENT) {
+		enum cil_log_level lvl = CIL_ERR;
+
+		if (optstack != NULL) {
+			lvl = CIL_WARN;
+
+			struct cil_optional *opt = (struct cil_optional *)optstack->data;
+			struct cil_tree_node *opt_node = opt->datum.nodes->head->data;
+			cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name);
+			/* disable an optional if something failed to resolve */
+			opt->enabled = CIL_FALSE;
+			rc = SEPOL_OK;
+		}
+
+		cil_tree_log(node, lvl, "Failed to resolve '%s' in %s statement", args->last_resolved_name, cil_node_to_string(node));
+		goto exit;
+	}
+
+	return rc;
+
+exit:
+	return rc;
+}
+
+int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_tree_node *optstack = NULL;
+	struct cil_tree_node *parent = NULL;
+	struct cil_tree_node *blockstack = NULL;
+	struct cil_tree_node *new = NULL;
+
+	if (current == NULL || extra_args == NULL) {
+		goto exit;
+	}
+
+	optstack = args->optstack;
+	parent = current->parent;
+	blockstack = args->blockstack;
+
+	if (parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
+		/* push this node onto a stack */
+		cil_tree_node_init(&new);
+
+		new->data = parent->data;
+		new->flavor = parent->flavor;
+
+		if (parent->flavor == CIL_OPTIONAL) {
+			if (optstack != NULL) {
+				optstack->parent = new;
+				new->cl_head = optstack;
+			}
+			args->optstack = new;
+		} else if (parent->flavor == CIL_BLOCK) {
+			if (blockstack != NULL) {
+				blockstack->parent = new;
+				new->cl_head = blockstack;
+			}
+			args->blockstack = new;
+		}
+	} else if (parent->flavor == CIL_BOOLEANIF) {
+		args->boolif = parent;
+	} else if (parent->flavor == CIL_MACRO) {
+		args->macro = parent;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+
+}
+
+int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_tree_node *parent = NULL;
+	struct cil_tree_node *blockstack = NULL;
+
+	if (current == NULL ||  extra_args == NULL) {
+		goto exit;
+	}
+
+	parent = current->parent;
+
+	if (parent->flavor == CIL_MACRO) {
+		args->macro = NULL;
+	} else if (parent->flavor == CIL_OPTIONAL) {
+		struct cil_tree_node *optstack;
+
+		if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) {
+			*(args->changed) = CIL_TRUE;
+			cil_tree_children_destroy(parent);
+		}
+
+		/* pop off the stack */
+		optstack = args->optstack;
+		args->optstack = optstack->cl_head;
+		if (optstack->cl_head) {
+			optstack->cl_head->parent = NULL;
+		}
+		free(optstack);
+	} else if (parent->flavor == CIL_BOOLEANIF) {
+		args->boolif = NULL;
+	} else if (parent->flavor == CIL_BLOCK) {
+		/* pop off the stack */
+		blockstack = args->blockstack;
+		args->blockstack = blockstack->cl_head;
+		if (blockstack->cl_head) {
+			blockstack->cl_head->parent = NULL;
+		}
+		free(blockstack);
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve extra_args;
+	enum cil_pass pass = CIL_PASS_TIF;
+	uint32_t changed = 0;
+
+	if (db == NULL || current == NULL) {
+		goto exit;
+	}
+
+	extra_args.db = db;
+	extra_args.pass = pass;
+	extra_args.changed = &changed;
+	extra_args.last_resolved_name = NULL;
+	extra_args.optstack = NULL;
+	extra_args.boolif= NULL;
+	extra_args.macro = NULL;
+	extra_args.sidorder_lists = NULL;
+	extra_args.classorder_lists = NULL;
+	extra_args.unordered_classorder_lists = NULL;
+	extra_args.catorder_lists = NULL;
+	extra_args.sensitivityorder_lists = NULL;
+	extra_args.in_list = NULL;
+	extra_args.blockstack = NULL;
+
+	cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
+	cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM);
+	cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM);
+	cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM);
+	cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
+	cil_list_init(&extra_args.in_list, CIL_IN);
+	for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
+		extra_args.pass = pass;
+		rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_INFO, "Pass %i of resolution failed\n", pass);
+			goto exit;
+		}
+
+		if (pass == CIL_PASS_IN) {
+			rc = cil_resolve_in_list(&extra_args);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			cil_list_destroy(&extra_args.in_list, CIL_FALSE);
+		}
+
+		if (pass == CIL_PASS_MISC1) {
+			db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL);
+			if (db->sidorder == NULL) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			db->classorder = __cil_ordered_lists_merge_all(&extra_args.classorder_lists, &extra_args.unordered_classorder_lists);
+			if (db->classorder == NULL) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			db->catorder = __cil_ordered_lists_merge_all(&extra_args.catorder_lists, NULL);
+			if (db->catorder == NULL) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			cil_set_cat_values(db->catorder, db);
+			db->sensitivityorder = __cil_ordered_lists_merge_all(&extra_args.sensitivityorder_lists, NULL);
+			if (db->sensitivityorder == NULL) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+
+			rc = __cil_verify_ordered(current, CIL_SID);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+
+			rc = __cil_verify_ordered(current, CIL_CLASS);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+
+			rc = __cil_verify_ordered(current, CIL_CAT);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+
+			rc = __cil_verify_ordered(current, CIL_SENS);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+
+		if (changed && (pass > CIL_PASS_CALL1)) {
+			/* Need to re-resolve because an optional was disabled that contained
+			 * one or more declarations. We only need to reset to the call1 pass 
+			 * because things done in the preceeding passes aren't allowed in 
+			 * optionals, and thus can't be disabled.
+			 * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment 
+			 * it to CIL_PASS_CALL2
+			 */
+			cil_log(CIL_INFO, "Resetting declarations\n");
+
+			if (pass >= CIL_PASS_MISC1) {
+				__cil_ordered_lists_reset(&extra_args.sidorder_lists);
+				__cil_ordered_lists_reset(&extra_args.classorder_lists);
+				__cil_ordered_lists_reset(&extra_args.unordered_classorder_lists);
+				__cil_ordered_lists_reset(&extra_args.catorder_lists);
+				__cil_ordered_lists_reset(&extra_args.sensitivityorder_lists);
+				cil_list_destroy(&db->sidorder, CIL_FALSE);
+				cil_list_destroy(&db->classorder, CIL_FALSE);
+				cil_list_destroy(&db->catorder, CIL_FALSE);
+				cil_list_destroy(&db->sensitivityorder, CIL_FALSE);
+			}
+
+			pass = CIL_PASS_CALL1;
+
+			rc = cil_reset_ast(current);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Failed to reset declarations\n");
+				goto exit;
+			}
+		}
+
+		/* reset the arguments */
+		changed = 0;
+		while (extra_args.optstack != NULL) {
+			struct cil_tree_node *curr = extra_args.optstack;
+			struct cil_tree_node *next = curr->cl_head;
+			free(curr);
+			extra_args.optstack = next;
+		}
+		while (extra_args.blockstack!= NULL) {
+			struct cil_tree_node *curr = extra_args.blockstack;
+			struct cil_tree_node *next = curr->cl_head;
+			free(curr);
+			extra_args.blockstack= next;
+		}
+	}
+
+	rc = __cil_verify_initsids(db->sidorder);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+exit:
+	__cil_ordered_lists_destroy(&extra_args.sidorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.classorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.catorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
+	cil_list_destroy(&extra_args.in_list, CIL_FALSE);
+
+	return rc;
+}
+
+static int __cil_resolve_name_with_root(struct cil_db *db, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+	symtab_t *symtab = &((struct cil_root *)db->ast->root->data)->symtab[sym_index];
+
+	return cil_symtab_get_datum(symtab, name, datum);
+}
+
+static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+	int rc = SEPOL_ERR;
+	symtab_t *symtab = NULL;
+
+	while (node != NULL && rc != SEPOL_OK) {
+		switch (node->flavor) {
+		case CIL_ROOT:
+			goto exit;
+			break;
+		case CIL_BLOCK:
+			symtab = &((struct cil_block*)node->data)->symtab[sym_index];
+			rc = cil_symtab_get_datum(symtab, name, datum);
+			break;
+		case CIL_BLOCKINHERIT: {
+			struct cil_blockinherit *inherit = node->data;
+			rc = __cil_resolve_name_with_parents(node->parent, name, sym_index, datum);
+			if (rc != SEPOL_OK) {
+				/* Continue search in original block's parent */
+				rc = __cil_resolve_name_with_parents(NODE(inherit->block), name, sym_index, datum);
+				goto exit;
+			}
+		}
+			break;
+		case CIL_MACRO: {
+			struct cil_macro *macro = node->data;
+			symtab = &macro->symtab[sym_index];
+			rc = cil_symtab_get_datum(symtab, name, datum);
+		}
+			break;
+		case CIL_CALL: {
+			struct cil_call *call = node->data;
+			rc = cil_resolve_name_call_args(call, name, sym_index, datum);
+			if (rc != SEPOL_OK) {
+				/* Continue search in macro's parent */
+				rc = __cil_resolve_name_with_parents(NODE(call->macro)->parent, name, sym_index, datum);
+			}
+		}
+			break;
+		case CIL_IN:
+			/* In block symtabs only exist before resolving the AST */
+		case CIL_CONDBLOCK:
+			/* Cond block symtabs only exist before resolving the AST */
+		default:
+			break;
+		}
+
+		node = node->parent;
+	}
+
+exit:
+	return rc;
+}
+
+static int __cil_resolve_name_helper(struct cil_db *db, struct cil_tree_node *node, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+	int rc = SEPOL_ERR;
+
+	rc = __cil_resolve_name_with_parents(node, name, sym_index, datum);
+	if (rc != SEPOL_OK) {
+		rc = __cil_resolve_name_with_root(db, name, sym_index, datum);
+	}
+	return rc;
+}
+
+int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum)
+{
+	int rc = SEPOL_ERR;
+	struct cil_args_resolve *args = extra_args;
+	struct cil_db *db = args->db;
+	struct cil_tree_node *node = NULL;
+
+	if (name == NULL) {
+		cil_log(CIL_ERR, "Invalid call to cil_resolve_name\n");
+		goto exit;
+	}
+
+	*datum = NULL;
+
+	if (strchr(name,'.') == NULL) {
+		/* No '.' in name */
+		rc = __cil_resolve_name_helper(db, ast_node->parent, name, sym_index, datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	} else {
+		char *sp = NULL;
+		char *name_dup = cil_strdup(name);
+		char *current = strtok_r(name_dup, ".", &sp);
+		char *next = strtok_r(NULL, ".", &sp);
+		symtab_t *symtab = NULL;
+		
+		node = ast_node;
+		if (*name == '.') {
+			/* Leading '.' */
+			symtab = &((struct cil_root *)db->ast->root->data)->symtab[CIL_SYM_BLOCKS];
+		} else {
+			rc = __cil_resolve_name_helper(db, node->parent, current, CIL_SYM_BLOCKS, datum);
+			if (rc != SEPOL_OK) {
+				free(name_dup);
+				goto exit;
+			}
+			symtab = (*datum)->symtab;
+		}
+		/* Keep looking up blocks by name until only last part of name remains */
+		while (next != NULL) {
+			rc = cil_symtab_get_datum(symtab, current, datum);
+			if (rc != SEPOL_OK) {
+				free(name_dup);
+				goto exit;
+			}
+			node = NODE(*datum);
+			if (node->flavor == CIL_BLOCK) {
+				symtab = &((struct cil_block*)node->data)->symtab[CIL_SYM_BLOCKS];
+			} else {
+				if (ast_node->flavor != CIL_IN) {
+					cil_log(CIL_WARN, "Can only use %s name for name resolution in \"in\" blocks\n", cil_node_to_string(node));
+					free(name_dup);
+					rc = SEPOL_ERR;
+					goto exit;
+				}
+				if (node->flavor == CIL_MACRO) {
+					struct cil_macro *macro = node->data;
+					symtab = &macro->symtab[sym_index];
+				} else {
+					/* optional */
+					symtab = (*datum)->symtab;
+				}
+			}
+			current = next;
+			next = strtok_r(NULL, ".", &sp);
+		}
+		symtab = &(symtab[sym_index]);
+		rc = cil_symtab_get_datum(symtab, current, datum);
+		free(name_dup);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	if (rc != SEPOL_OK) {
+		*datum = NULL;
+	}
+
+	if (*datum != NULL) {
+		/* If this datum is an alias, then return the actual node
+		 * This depends on aliases already being processed
+		 */
+		node = NODE(*datum);
+		if (node->flavor == CIL_TYPEALIAS || node->flavor == CIL_SENSALIAS
+			|| node->flavor == CIL_CATALIAS) {
+			struct cil_alias *alias = (struct cil_alias *)(*datum);
+			if (alias->actual) {
+				*datum = alias->actual;
+			}
+		}
+	}
+
+	args->last_resolved_name = name;
+
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
new file mode 100644
index 0000000..1175f97
--- /dev/null
+++ b/libsepol/cil/src/cil_resolve_ast.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_RESOLVE_AST_H_
+#define CIL_RESOLVE_AST_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+
+int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classperms(struct cil_tree_node *current, struct cil_classperms *cp, void *extra_args);
+int cil_resolve_classpermissionset(struct cil_tree_node *current, struct cil_classpermissionset *cps, void *extra_args);
+int cil_resolve_classperms_list(struct cil_tree_node *current, struct cil_list *cp_list, void *extra_args);
+int cil_resolve_avrule(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typealias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typebounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typepermissive(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_rangetransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classmapping(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userrole(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userbounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roletype(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roleallow(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_rolebounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sensalias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_catalias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_cat_list(struct cil_tree_node *current, struct cil_list *cat_list, struct cil_list *res_cat_list, void *extra_args);
+int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args);
+int cil_resolve_senscat(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_level(struct cil_tree_node *current, struct cil_level *level, void *extra_args); 
+int cil_resolve_levelrange(struct cil_tree_node *current, struct cil_levelrange *levelrange, void *extra_args); 
+int cil_resolve_constrain(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args);
+int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_netifcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_iomemcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_ioportcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_pcidevicecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_fsuse(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sidcontext(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_blockinherit(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_in(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_call1(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_call2(struct cil_tree_node *, void *extra_args);
+int cil_resolve_name_call_args(struct cil_call *call, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum);
+int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struct cil_list **datum_expr, struct cil_tree_node *parent, void *extra_args);
+int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args);
+int cil_evaluate_expr(struct cil_list *datum_expr, uint16_t *result);
+int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args);
+
+int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current);
+int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum);
+
+#endif /* CIL_RESOLVE_AST_H_ */
diff --git a/libsepol/cil/src/cil_stack.c b/libsepol/cil/src/cil_stack.c
new file mode 100644
index 0000000..bbfb961
--- /dev/null
+++ b/libsepol/cil/src/cil_stack.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_stack.h"
+
+
+#define CIL_STACK_INIT_SIZE 16
+
+void cil_stack_init(struct cil_stack **stack)
+{
+	struct cil_stack *new_stack = cil_malloc(sizeof(*new_stack));
+	new_stack->stack = cil_malloc(sizeof(*(new_stack->stack)) * CIL_STACK_INIT_SIZE);
+	new_stack->size = CIL_STACK_INIT_SIZE;
+	new_stack->pos = -1;
+	*stack = new_stack;
+}
+
+void cil_stack_destroy(struct cil_stack **stack)
+{
+	if (stack == NULL || *stack == NULL) {
+		return;
+	}
+
+	free((*stack)->stack);
+	free(*stack);
+	*stack = NULL;
+}
+
+void cil_stack_empty(struct cil_stack *stack)
+{
+	stack->pos = -1;
+}
+
+int cil_stack_is_empty(struct cil_stack *stack)
+{
+	return (stack->pos == -1);
+}
+
+void cil_stack_push(struct cil_stack *stack, enum cil_flavor flavor, void *data)
+{
+	stack->pos++;
+
+	if (stack->pos == stack->size) {
+		stack->size *= 2;
+		stack->stack = cil_realloc(stack->stack, sizeof(*stack->stack) * stack->size);
+	}
+
+	stack->stack[stack->pos].flavor = flavor;
+	stack->stack[stack->pos].data = data;
+}
+
+struct cil_stack_item *cil_stack_pop(struct cil_stack *stack)
+{
+	if (stack->pos == -1) {
+		return NULL;
+	}
+
+	stack->pos--;
+	return &stack->stack[stack->pos + 1];
+}
+
+struct cil_stack_item *cil_stack_peek(struct cil_stack *stack)
+{
+	if (stack->pos < 0) {
+		return NULL;
+	}
+
+	return &stack->stack[stack->pos];
+}
+
+struct cil_stack_item *cil_stack_peek_at(struct cil_stack *stack, int pos)
+{
+	int peekpos = stack->pos - pos;
+
+	if (peekpos < 0 || peekpos > stack->pos) {
+		return NULL;
+	}
+
+	return &stack->stack[peekpos];
+}
diff --git a/libsepol/cil/src/cil_stack.h b/libsepol/cil/src/cil_stack.h
new file mode 100644
index 0000000..b78535a
--- /dev/null
+++ b/libsepol/cil/src/cil_stack.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_STACK_H_
+#define CIL_STACK_H_
+
+struct cil_stack {
+	struct cil_stack_item *stack;
+	int size;
+	int pos;
+};
+
+struct cil_stack_item {
+	enum cil_flavor flavor;
+	void *data;
+};
+
+#define cil_stack_for_each_starting_at(stack, start, pos, item) \
+	for (pos = start, item = cil_stack_peek_at(stack, pos); item != NULL; pos++, item = cil_stack_peek_at(stack, pos))
+
+#define cil_stack_for_each(stack, pos, item) cil_stack_for_each_starting_at(stack, 0, pos, item)
+
+
+void cil_stack_init(struct cil_stack **stack);
+void cil_stack_destroy(struct cil_stack **stack);
+
+void cil_stack_empty(struct cil_stack *stack);
+int cil_stack_is_empty(struct cil_stack *stack);
+
+void cil_stack_push(struct cil_stack *stack, enum cil_flavor flavor, void *data);
+struct cil_stack_item *cil_stack_pop(struct cil_stack *stack);
+struct cil_stack_item *cil_stack_peek(struct cil_stack *stack);
+struct cil_stack_item *cil_stack_peek_at(struct cil_stack *stack, int pos);
+
+
+#endif
diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c
new file mode 100644
index 0000000..ad2a334
--- /dev/null
+++ b/libsepol/cil/src/cil_strpool.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2014 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "cil_mem.h"
+#include "cil_strpool.h"
+
+#include "cil_log.h"
+#define CIL_STRPOOL_TABLE_SIZE 1 << 15
+
+struct cil_strpool_entry {
+	char *str;
+};
+
+static hashtab_t cil_strpool_tab = NULL;
+
+static unsigned int cil_strpool_hash(hashtab_t h, hashtab_key_t key)
+{
+	char *p, *keyp;
+	size_t size;
+	unsigned int val;
+
+	val = 0;
+	keyp = (char*)key;
+	size = strlen(keyp);
+	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+		val =
+		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+	return val & (h->size - 1);
+}
+
+static int cil_strpool_compare(hashtab_t h __attribute__ ((unused)), hashtab_key_t key1, hashtab_key_t key2)
+{
+	char *keyp1 = (char*)key1;
+	char *keyp2 = (char*)key2;
+	return strcmp(keyp1, keyp2);
+}
+
+char *cil_strpool_add(const char *str)
+{
+	struct cil_strpool_entry *strpool_ref = NULL;
+
+	strpool_ref = hashtab_search(cil_strpool_tab, (hashtab_key_t)str);
+	if (strpool_ref == NULL) {
+		strpool_ref = cil_malloc(sizeof(*strpool_ref));
+		strpool_ref->str = cil_strdup(str);
+		int rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref);
+		if (rc != SEPOL_OK) {
+			(*cil_mem_error_handler)();
+		}
+	}
+
+	return strpool_ref->str;
+}
+
+static int cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
+{
+	struct cil_strpool_entry *strpool_ref = (struct cil_strpool_entry*)d;
+	free(strpool_ref->str);
+	free(strpool_ref);
+	return SEPOL_OK;
+}
+
+void cil_strpool_init(void)
+{
+	cil_strpool_tab = hashtab_create(cil_strpool_hash, cil_strpool_compare, CIL_STRPOOL_TABLE_SIZE);
+	if (cil_strpool_tab == NULL) {
+		(*cil_mem_error_handler)();
+	}
+}
+
+void cil_strpool_destroy(void)
+{
+	hashtab_map(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
+	hashtab_destroy(cil_strpool_tab);
+}
diff --git a/libsepol/cil/src/cil_strpool.h b/libsepol/cil/src/cil_strpool.h
new file mode 100644
index 0000000..a61a2d9
--- /dev/null
+++ b/libsepol/cil/src/cil_strpool.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_STRPOOL_H_
+#define CIL_STRPOOL_H_
+
+#include <sepol/policydb/hashtab.h>
+
+char *cil_strpool_add(const char *str);
+void cil_strpool_init(void);
+void cil_strpool_destroy(void);
+#endif /* CIL_STRPOOL_H_ */
diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c
new file mode 100644
index 0000000..3769979
--- /dev/null
+++ b/libsepol/cil/src/cil_symtab.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sepol/errcodes.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/symtab.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+#include "cil_mem.h"
+#include "cil_strpool.h"
+#include "cil_log.h"
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_symtab_error(const char* msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	cil_vlog(CIL_ERR, msg, ap);
+	va_end(ap);
+	exit(1);
+}
+
+void cil_symtab_init(symtab_t *symtab, unsigned int size)
+{
+	int rc = symtab_init(symtab, size);
+	if (rc != SEPOL_OK) {
+		cil_symtab_error("Failed to create symtab\n");
+	}
+}
+
+void cil_symtab_datum_init(struct cil_symtab_datum *datum)
+{
+	datum->name = NULL;
+	datum->fqn = NULL;
+	datum->symtab = NULL;
+	cil_list_init(&datum->nodes, CIL_LIST_ITEM);
+}
+
+void cil_symtab_datum_destroy(struct cil_symtab_datum *datum)
+{
+	cil_list_destroy(&datum->nodes, 0);
+	cil_symtab_remove_datum(datum);
+}
+
+void cil_symtab_datum_remove_node(struct cil_symtab_datum *datum, struct cil_tree_node *node)
+{
+	if (datum && datum->nodes != NULL) {
+		cil_list_remove(datum->nodes, CIL_NODE, node, 0);
+		if (datum->nodes->head == NULL) {
+			cil_symtab_datum_destroy(datum);
+		}
+	}
+}
+
+/* This both initializes the datum and inserts it into the symtab.
+   Note that cil_symtab_datum_destroy() is the analog to the initializer portion */
+int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node)
+{
+	int rc = hashtab_insert(symtab->table, key, (hashtab_datum_t)datum);
+	if (rc == SEPOL_OK) {
+		datum->name = key;
+		datum->fqn = key;
+		datum->symtab = symtab;
+		cil_list_append(datum->nodes, CIL_NODE, node);
+	} else if (rc == SEPOL_EEXIST) {
+		cil_list_append(datum->nodes, CIL_NODE, node);
+	} else {
+		cil_symtab_error("Failed to insert datum into hashtab\n");
+	}
+
+	return rc;
+}
+
+void cil_symtab_remove_datum(struct cil_symtab_datum *datum)
+{
+	symtab_t *symtab = datum->symtab;
+
+	if (symtab == NULL) {
+		return;
+	}
+
+	hashtab_remove(symtab->table, datum->name, NULL, NULL);
+	datum->symtab = NULL;
+}
+
+int cil_symtab_get_datum(symtab_t *symtab, char *key, struct cil_symtab_datum **datum)
+{
+	*datum = (struct cil_symtab_datum*)hashtab_search(symtab->table, (hashtab_key_t)key);
+	if (*datum == NULL) {
+		return SEPOL_ENOENT;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_symtab_map(symtab_t *symtab,
+				   int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args),
+				   void *args)
+{
+	return hashtab_map(symtab->table, apply, args);
+}
+
+static int __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
+{
+	struct cil_symtab_datum *datum = d;
+	datum->symtab = NULL;
+	return SEPOL_OK;
+}
+
+void cil_symtab_destroy(symtab_t *symtab)
+{
+	if (symtab->table != NULL){
+		cil_symtab_map(symtab, __cil_symtab_destroy_helper, NULL);
+		hashtab_destroy(symtab->table);
+		symtab->table = NULL;
+	}
+}
+
+void cil_complex_symtab_hash(struct cil_complex_symtab_key *ckey, int mask, intptr_t *hash)
+{
+	intptr_t sum = ckey->key1 + ckey->key2 + ckey->key3 + ckey->key4;
+	*hash = (intptr_t)((sum >> 2) & mask);
+}
+
+void cil_complex_symtab_init(struct cil_complex_symtab *symtab, unsigned int size)
+{
+	symtab->htable = cil_calloc(size, sizeof(struct cil_complex_symtab *));
+
+	symtab->nelems = 0;
+	symtab->nslots = size;
+	symtab->mask = size - 1;
+}
+
+int cil_complex_symtab_insert(struct cil_complex_symtab *symtab,
+			struct cil_complex_symtab_key *ckey,
+			struct cil_complex_symtab_datum *datum)
+{
+	intptr_t hash;
+	struct cil_complex_symtab_node *node = NULL;
+	struct cil_complex_symtab_node *prev = NULL;
+	struct cil_complex_symtab_node *curr = NULL;
+
+	node = cil_malloc(sizeof(*node));
+	memset(node, 0, sizeof(*node));
+
+	node->ckey = ckey;
+	node->datum = datum;
+
+	cil_complex_symtab_hash(ckey, symtab->mask, &hash);
+
+	for (prev = NULL, curr = symtab->htable[hash]; curr != NULL;
+		prev = curr, curr = curr->next) {
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 == curr->ckey->key3 &&
+			ckey->key4 == curr->ckey->key4) {
+			return SEPOL_EEXIST;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 < curr->ckey->key2) {
+			break;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 < curr->ckey->key3) {
+			break;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 == curr->ckey->key3 &&
+			ckey->key4 < curr->ckey->key4) {
+			break;
+		}
+	}
+
+	if (prev != NULL) {
+		node->next = prev->next;
+		prev->next = node;
+	} else {
+		node->next = symtab->htable[hash];
+		symtab->htable[hash] = node;
+	}
+
+	symtab->nelems++;
+
+	return SEPOL_OK;
+}
+
+void cil_complex_symtab_search(struct cil_complex_symtab *symtab,
+			       struct cil_complex_symtab_key *ckey,
+			       struct cil_complex_symtab_datum **out)
+{
+	intptr_t hash;
+	struct cil_complex_symtab_node *curr = NULL;
+
+	cil_complex_symtab_hash(ckey, symtab->mask, &hash);
+	for (curr = symtab->htable[hash]; curr != NULL; curr = curr->next) {
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 == curr->ckey->key3 &&
+			ckey->key4 == curr->ckey->key4) {
+			*out = curr->datum;
+			return;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 < curr->ckey->key2) {
+			break;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 < curr->ckey->key3) {
+			break;
+		}
+
+		if (ckey->key1 == curr->ckey->key1 &&
+			ckey->key2 == curr->ckey->key2 &&
+			ckey->key3 == curr->ckey->key3 &&
+			ckey->key4 < curr->ckey->key4) {
+			break;
+		}
+	}
+
+	*out = NULL;
+}
+
+void cil_complex_symtab_destroy(struct cil_complex_symtab *symtab)
+{
+	struct cil_complex_symtab_node *curr = NULL;
+	struct cil_complex_symtab_node *temp = NULL;
+	unsigned int i;
+
+	if (symtab == NULL) {
+		return;
+	}
+
+	for (i = 0; i < symtab->nslots; i++) {
+		curr = symtab->htable[i];
+		while (curr != NULL) {
+			temp = curr;
+			curr = curr->next;
+			free(temp);
+		}
+		symtab->htable[i] = NULL;
+	}
+	free(symtab->htable);
+	symtab->htable = NULL;
+	symtab->nelems = 0;
+	symtab->nslots = 0;
+	symtab->mask = 0;
+}
diff --git a/libsepol/cil/src/cil_symtab.h b/libsepol/cil/src/cil_symtab.h
new file mode 100644
index 0000000..efb63e7
--- /dev/null
+++ b/libsepol/cil/src/cil_symtab.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef __CIL_SYMTAB_H_
+#define __CIL_SYMTAB_H_
+
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/hashtab.h>
+
+#include "cil_tree.h"
+
+struct cil_symtab_datum {
+	struct cil_list *nodes;
+	char *name;
+	char *fqn;
+	symtab_t *symtab;
+};
+
+#define DATUM(d) ((struct cil_symtab_datum *)(d))
+#define NODE(n) ((struct cil_tree_node *)(DATUM(n)->nodes->head->data))
+#define FLAVOR(f) (NODE(f)->flavor)
+
+struct cil_complex_symtab_key {
+	intptr_t key1;
+	intptr_t key2;
+	intptr_t key3;
+	intptr_t key4;
+};
+
+struct cil_complex_symtab_datum {
+	void *data;
+};
+
+struct cil_complex_symtab_node {
+	struct cil_complex_symtab_key *ckey;
+	struct cil_complex_symtab_datum *datum;
+	struct cil_complex_symtab_node *next;
+};
+
+struct cil_complex_symtab {
+	struct cil_complex_symtab_node **htable;
+	uint32_t nelems;
+	uint32_t nslots;
+	uint32_t mask;
+};
+
+void cil_symtab_init(symtab_t *symtab, unsigned int size);
+void cil_symtab_datum_init(struct cil_symtab_datum *datum);
+void cil_symtab_datum_destroy(struct cil_symtab_datum *datum);
+void cil_symtab_datum_remove_node(struct cil_symtab_datum *datum, struct cil_tree_node *node);
+int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node);
+void cil_symtab_remove_datum(struct cil_symtab_datum *datum);
+int cil_symtab_get_datum(symtab_t *symtab, char *key, struct cil_symtab_datum **datum);
+int cil_symtab_map(symtab_t *symtab,
+				   int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args),
+				   void *args);
+void cil_symtab_destroy(symtab_t *symtab);
+void cil_complex_symtab_init(struct cil_complex_symtab *symtab, unsigned int size);
+int cil_complex_symtab_insert(struct cil_complex_symtab *symtab, struct cil_complex_symtab_key *ckey, struct cil_complex_symtab_datum *datum);
+void cil_complex_symtab_search(struct cil_complex_symtab *symtab, struct cil_complex_symtab_key *ckey, struct cil_complex_symtab_datum **out);
+void cil_complex_symtab_destroy(struct cil_complex_symtab *symtab);
+
+#endif
diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
new file mode 100644
index 0000000..9ff9d4b
--- /dev/null
+++ b/libsepol/cil/src/cil_tree.c
@@ -0,0 +1,1749 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_parser.h"
+#include "cil_strpool.h"
+
+void cil_tree_print_perms_list(struct cil_tree_node *current_perm);
+void cil_tree_print_classperms(struct cil_classperms *cp);
+void cil_tree_print_level(struct cil_level *level);
+void cil_tree_print_levelrange(struct cil_levelrange *lvlrange);
+void cil_tree_print_context(struct cil_context *context);
+void cil_tree_print_expr_tree(struct cil_tree_node *expr_root);
+void cil_tree_print_constrain(struct cil_constrain *cons);
+void cil_tree_print_node(struct cil_tree_node *node);
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_error(const char* msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	cil_vlog(CIL_ERR, msg, ap);
+	va_end(ap);
+	exit(1);
+}
+
+struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil)
+{
+	if (!node) {
+		return NULL;
+	}
+
+	node = node->parent;
+
+	while (node) {
+		if (node->flavor == CIL_NODE && node->data == NULL) {
+			if (node->cl_head->data == CIL_KEY_SRC_INFO) {
+				/* Parse Tree */
+				*path = node->cl_head->next->next->data;
+				*is_cil = (node->cl_head->next->data == CIL_KEY_SRC_CIL);
+				return node;
+			}
+			node = node->parent;
+		} else if (node->flavor == CIL_SRC_INFO) {
+				/* AST */
+				struct cil_src_info *info = node->data;
+				*path = info->path;
+				*is_cil = info->is_cil;
+				return node;
+		} else {
+			if (node->flavor == CIL_CALL) {
+				struct cil_call *call = node->data;
+				node = NODE(call->macro);
+			} else if (node->flavor == CIL_BLOCKINHERIT) {
+				struct cil_blockinherit *inherit = node->data;
+				node = NODE(inherit->block);
+			} else {
+				node = node->parent;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+char *cil_tree_get_cil_path(struct cil_tree_node *node)
+{
+	char *path = NULL;
+	int is_cil;
+
+	while (node) {
+		node = cil_tree_get_next_path(node, &path, &is_cil);
+		if (node && is_cil) {
+			return path;
+		}
+	}
+
+	return NULL;
+}
+
+__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	cil_vlog(lvl, msg, ap);
+	va_end(ap);
+
+	if (node) {
+		char *path = NULL;
+		int is_cil;
+		unsigned hll_line = node->hll_line;
+
+		path = cil_tree_get_cil_path(node);
+
+		if (path != NULL) {
+			cil_log(lvl, " at %s:%d", path, node->line);
+		}
+
+		while (node) {
+			node = cil_tree_get_next_path(node, &path, &is_cil);
+			if (node && !is_cil) {
+				cil_log(lvl," from %s:%d", path, hll_line);
+				path = NULL;
+				hll_line = node->hll_line;
+			}
+		}
+	}
+
+	cil_log(lvl,"\n");
+}
+
+int cil_tree_init(struct cil_tree **tree)
+{
+	struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree));
+
+	cil_tree_node_init(&new_tree->root);
+	
+	*tree = new_tree;
+	
+	return SEPOL_OK;
+}
+
+void cil_tree_destroy(struct cil_tree **tree)
+{
+	if (tree == NULL || *tree == NULL) {
+		return;
+	}
+
+	cil_tree_subtree_destroy((*tree)->root);
+	free(*tree);
+	*tree = NULL;
+}
+
+void cil_tree_subtree_destroy(struct cil_tree_node *node)
+{
+	cil_tree_children_destroy(node);
+	cil_tree_node_destroy(&node);
+}
+
+void cil_tree_children_destroy(struct cil_tree_node *node)
+{
+	struct cil_tree_node *start_node = node;
+	struct cil_tree_node *next = NULL;
+
+	if (node == NULL) {
+		return;
+	}
+
+	if (node->cl_head != NULL) {
+		node = node->cl_head;
+	}
+
+	while (node != start_node) {
+		if (node->cl_head != NULL){
+			next = node->cl_head;
+		} else {
+			if (node->next == NULL) {
+				next = node->parent;
+				if (node->parent != NULL) {
+					node->parent->cl_head = NULL;
+				}
+				cil_tree_node_destroy(&node);
+			} else {
+				next = node->next;
+				cil_tree_node_destroy(&node);
+			}
+		}
+		node = next;
+	}
+}
+
+void cil_tree_node_init(struct cil_tree_node **node)
+{
+	struct cil_tree_node *new_node = cil_malloc(sizeof(*new_node));
+	new_node->cl_head = NULL;
+	new_node->cl_tail = NULL;
+	new_node->parent = NULL;
+	new_node->data = NULL;
+	new_node->next = NULL;
+	new_node->flavor = CIL_ROOT;
+	new_node->line = 0;
+	new_node->hll_line = 0;
+
+	*node = new_node;
+}
+
+void cil_tree_node_destroy(struct cil_tree_node **node)
+{
+	struct cil_symtab_datum *datum;
+
+	if (node == NULL || *node == NULL) {
+		return;
+	}
+
+	if ((*node)->flavor >= CIL_MIN_DECLARATIVE) {
+		datum = (*node)->data;
+		cil_symtab_datum_remove_node(datum, *node);
+		if (datum->nodes == NULL) {
+			cil_destroy_data(&(*node)->data, (*node)->flavor);
+		}
+	} else {
+		cil_destroy_data(&(*node)->data, (*node)->flavor);
+	}
+	free(*node);
+	*node = NULL;
+}
+
+/* Perform depth-first walk of the tree
+   Parameters:
+   start_node:          root node to start walking from
+   process_node:        function to call when visiting a node
+                        Takes parameters:
+                            node:     node being visited
+                            finished: boolean indicating to the tree walker that it should move on from this branch
+                            extra_args:    additional data
+   first_child:		Function to call before entering list of children
+                        Takes parameters:
+                            node:     node of first child
+                            extra args:     additional data
+   last_child:		Function to call when finished with the last child of a node's children
+   extra_args:               any additional data to be passed to the helper functions
+*/
+
+int cil_tree_walk_core(struct cil_tree_node *node,
+					   int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args),
+					   int (*first_child)(struct cil_tree_node *node, void *extra_args), 
+					   int (*last_child)(struct cil_tree_node *node, void *extra_args), 
+					   void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	while (node) {
+		uint32_t finished = CIL_TREE_SKIP_NOTHING;
+
+		if (process_node != NULL) {
+			rc = (*process_node)(node, &finished, extra_args);
+			if (rc != SEPOL_OK) {
+				cil_tree_log(node, CIL_INFO, "Problem");
+				return rc;
+			}
+		}
+
+		if (finished & CIL_TREE_SKIP_NEXT) {
+			return SEPOL_OK;
+		}
+
+		if (node->cl_head != NULL && !(finished & CIL_TREE_SKIP_HEAD)) {
+			rc = cil_tree_walk(node, process_node, first_child, last_child, extra_args);
+			if (rc != SEPOL_OK) {
+				return rc;
+			}
+		}
+
+		node = node->next;
+	}
+
+	return SEPOL_OK;
+}
+
+int cil_tree_walk(struct cil_tree_node *node, 
+				  int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), 
+				  int (*first_child)(struct cil_tree_node *node, void *extra_args), 
+				  int (*last_child)(struct cil_tree_node *node, void *extra_args), 
+				  void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	if (!node || !node->cl_head) {
+		return SEPOL_OK;
+	}
+
+	if (first_child != NULL) {
+		rc = (*first_child)(node->cl_head, extra_args);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_INFO, "Problem");
+			return rc;
+		}
+	}
+
+	rc = cil_tree_walk_core(node->cl_head, process_node, first_child, last_child, extra_args);
+	if (rc != SEPOL_OK) {
+		return rc;
+	}
+
+	if (last_child != NULL) {
+		rc = (*last_child)(node->cl_tail, extra_args);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_INFO, "Problem");
+			return rc;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+
+/* Copied from cil_policy.c, but changed to prefix -- Need to refactor */
+static int cil_expr_to_string(struct cil_list *expr, char **out)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	char *stack[COND_EXPR_MAXDEPTH] = {};
+	int pos = 0;
+
+	cil_list_for_each(curr, expr) {
+		if (pos > COND_EXPR_MAXDEPTH) {
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		switch (curr->flavor) {
+		case CIL_LIST:
+			rc = cil_expr_to_string(curr->data, &stack[pos]);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+			pos++;
+			break;
+		case CIL_STRING:
+			stack[pos] = curr->data;
+			pos++;
+			break;
+		case CIL_DATUM:
+			stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
+			pos++;
+			break;
+		case CIL_OP: {
+			int len;
+			char *expr_str;
+			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+			char *op_str = NULL;
+
+			if (pos == 0) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			switch (op_flavor) {
+			case CIL_AND:
+				op_str = CIL_KEY_AND;
+				break;
+			case CIL_OR:
+				op_str = CIL_KEY_OR;
+				break;
+			case CIL_NOT:
+				op_str = CIL_KEY_NOT;
+				break;
+			case CIL_ALL:
+				op_str = CIL_KEY_ALL;
+				break;
+			case CIL_EQ:
+				op_str = CIL_KEY_EQ;
+				break;
+			case CIL_NEQ:
+				op_str = CIL_KEY_NEQ;
+				break;
+			case CIL_XOR:
+				op_str = CIL_KEY_XOR;
+				break;
+			case CIL_RANGE:
+				op_str = CIL_KEY_RANGE;
+				break;
+			case CIL_CONS_DOM:
+				op_str = CIL_KEY_CONS_DOM;
+				break;
+			case CIL_CONS_DOMBY:
+				op_str = CIL_KEY_CONS_DOMBY;
+				break;
+			case CIL_CONS_INCOMP:
+				op_str = CIL_KEY_CONS_INCOMP;
+				break;
+			default:
+				cil_log(CIL_ERR, "Unknown operator in expression\n");
+				goto exit;
+				break;
+			}
+			if (op_flavor == CIL_NOT) {
+				len = strlen(stack[pos-1]) + strlen(op_str) + 4;
+				expr_str = cil_malloc(len);
+				snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
+				free(stack[pos-1]);
+				stack[pos-1] = NULL;
+				pos--;
+			} else {
+				if (pos < 2) {
+					rc = SEPOL_ERR;
+					goto exit;
+				}
+				len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
+				expr_str = cil_malloc(len);
+				snprintf(expr_str, len, "(%s %s %s)", op_str, stack[pos-1], stack[pos-2]);
+				free(stack[pos-2]);
+				free(stack[pos-1]);
+				stack[pos-2] = NULL;
+				stack[pos-1] = NULL;
+				pos -= 2;
+			}
+			stack[pos] = expr_str;
+			pos++;
+			break;
+		}
+		case CIL_CONS_OPERAND: {
+			enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
+			char *operand_str = NULL;
+			switch (operand_flavor) {
+			case CIL_CONS_U1:
+				operand_str = CIL_KEY_CONS_U1;
+				break;
+			case CIL_CONS_U2:
+				operand_str = CIL_KEY_CONS_U2;
+				break;
+			case CIL_CONS_U3:
+				operand_str = CIL_KEY_CONS_U3;
+				break;
+			case CIL_CONS_T1:
+				operand_str = CIL_KEY_CONS_T1;
+				break;
+			case CIL_CONS_T2:
+				operand_str = CIL_KEY_CONS_T2;
+				break;
+			case CIL_CONS_T3:
+				operand_str = CIL_KEY_CONS_T3;
+				break;
+			case CIL_CONS_R1:
+				operand_str = CIL_KEY_CONS_R1;
+				break;
+			case CIL_CONS_R2:
+				operand_str = CIL_KEY_CONS_R2;
+				break;
+			case CIL_CONS_R3:
+				operand_str = CIL_KEY_CONS_R3;
+				break;
+			case CIL_CONS_L1:
+				operand_str = CIL_KEY_CONS_L1;
+				break;
+			case CIL_CONS_L2:
+				operand_str = CIL_KEY_CONS_L2;
+				break;
+			case CIL_CONS_H1:
+				operand_str = CIL_KEY_CONS_H1;
+				break;
+			case CIL_CONS_H2:
+				operand_str = CIL_KEY_CONS_H2;
+				break;
+			default:
+				cil_log(CIL_ERR, "Unknown operand in expression\n");
+				goto exit;
+				break;
+			}
+			stack[pos] = operand_str;
+			pos++;
+			break;
+		}
+		default:
+			cil_log(CIL_ERR, "Unknown flavor in expression\n");
+			goto exit;
+			break;
+		}
+	}
+
+	*out = stack[0];
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+void cil_tree_print_expr(struct cil_list *datum_expr, struct cil_list *str_expr)
+{
+	char *expr_str;
+
+	cil_log(CIL_INFO, "(");
+
+	if (datum_expr != NULL) {
+		cil_expr_to_string(datum_expr, &expr_str);
+	} else {
+		cil_expr_to_string(str_expr, &expr_str);
+	}
+
+	cil_log(CIL_INFO, "%s)", expr_str);
+	free(expr_str);
+}
+
+void cil_tree_print_perms_list(struct cil_tree_node *current_perm)
+{
+	while (current_perm != NULL) {
+		if (current_perm->flavor == CIL_PERM) {
+			cil_log(CIL_INFO, " %s", ((struct cil_perm *)current_perm->data)->datum.name);
+		} else if (current_perm->flavor == CIL_MAP_PERM) {
+			cil_log(CIL_INFO, " %s", ((struct cil_perm*)current_perm->data)->datum.name);
+		} else {
+			cil_log(CIL_INFO, "\n\n perms list contained unexpected data type: %d\n", current_perm->flavor);
+			break;
+		}
+		current_perm = current_perm->next;	
+	}
+}
+
+void cil_tree_print_cats(struct cil_cats *cats)
+{
+	cil_tree_print_expr(cats->datum_expr, cats->str_expr);
+}
+
+void cil_tree_print_perm_strs(struct cil_list *perm_strs)
+{
+	struct cil_list_item *curr;
+
+	if (perm_strs == NULL) {
+		return;
+	}
+
+	cil_log(CIL_INFO, " (");
+
+	cil_list_for_each(curr, perm_strs) {
+		cil_log(CIL_INFO, " %s", (char*)curr->data);
+	}
+
+	cil_log(CIL_INFO, " )");
+}
+
+
+void cil_tree_print_classperms(struct cil_classperms *cp)
+{
+	if (cp == NULL) {
+		return;
+	}
+
+	cil_log(CIL_INFO, " class: %s", cp->class_str);
+	cil_log(CIL_INFO, ", perm_strs:");
+	cil_tree_print_perm_strs(cp->perm_strs);
+}
+
+void cil_tree_print_classperms_set(struct cil_classperms_set *cp_set)
+{
+	if (cp_set == NULL) {
+		return;
+	}
+
+	cil_log(CIL_INFO, " %s", cp_set->set_str);
+}
+
+void cil_tree_print_classperms_list(struct cil_list *cp_list)
+{
+	struct cil_list_item *i;
+
+	if (cp_list == NULL) {
+		return;
+	}
+
+	cil_list_for_each(i, cp_list) {
+		if (i->flavor == CIL_CLASSPERMS) {
+			cil_tree_print_classperms(i->data);
+		} else {
+			cil_tree_print_classperms_set(i->data);
+		}
+	}
+}
+
+void cil_tree_print_level(struct cil_level *level)
+{
+	if (level->sens != NULL) {
+		cil_log(CIL_INFO, " %s", level->sens->datum.name);
+	} else if (level->sens_str != NULL) {
+		cil_log(CIL_INFO, " %s", level->sens_str);
+	}
+
+	cil_tree_print_cats(level->cats);
+
+	return;
+}
+
+void cil_tree_print_levelrange(struct cil_levelrange *lvlrange)
+{
+	cil_log(CIL_INFO, " (");
+	if (lvlrange->low != NULL) {
+		cil_log(CIL_INFO, " (");
+		cil_tree_print_level(lvlrange->low);
+		cil_log(CIL_INFO, " )");
+	} else if (lvlrange->low_str != NULL) {
+		cil_log(CIL_INFO, " %s", lvlrange->low_str);
+	}
+
+	if (lvlrange->high != NULL) {
+		cil_log(CIL_INFO, " (");
+		cil_tree_print_level(lvlrange->high);
+		cil_log(CIL_INFO, " )");
+	} else if (lvlrange->high_str != NULL) {
+		cil_log(CIL_INFO, " %s", lvlrange->high_str);
+	}
+	cil_log(CIL_INFO, " )");
+}
+
+void cil_tree_print_context(struct cil_context *context)
+{
+	cil_log(CIL_INFO, " (");
+	if (context->user != NULL) {
+		cil_log(CIL_INFO, " %s", context->user->datum.name);
+	} else if (context->user_str != NULL) {
+		cil_log(CIL_INFO, " %s", context->user_str);
+	}
+
+	if (context->role != NULL) {
+		cil_log(CIL_INFO, " %s", context->role->datum.name);
+	} else if (context->role_str != NULL) {
+		cil_log(CIL_INFO, " %s", context->role_str);
+	}
+
+	if (context->type != NULL) {
+		cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)context->type)->name);
+	} else if (context->type_str != NULL) {
+		cil_log(CIL_INFO, " %s", context->type_str);
+	}
+
+	if (context->range != NULL) {
+		cil_tree_print_levelrange(context->range);
+	} else if (context->range_str != NULL) {
+		cil_log(CIL_INFO, " %s", context->range_str);
+	}
+
+	cil_log(CIL_INFO, " )");
+
+	return;
+}
+
+void cil_tree_print_constrain(struct cil_constrain *cons)
+{
+	cil_tree_print_classperms_list(cons->classperms);
+
+	cil_tree_print_expr(cons->datum_expr, cons->str_expr);
+
+	cil_log(CIL_INFO, "\n");
+}
+
+void cil_tree_print_node(struct cil_tree_node *node)
+{
+	if (node->data == NULL) {
+		cil_log(CIL_INFO, "FLAVOR: %d", node->flavor);
+		return;
+	} else {
+		switch( node->flavor ) {
+		case CIL_BLOCK: {
+			struct cil_block *block = node->data;
+			cil_log(CIL_INFO, "BLOCK: %s\n", block->datum.name);
+			return;
+		}
+		case CIL_BLOCKINHERIT: {
+			struct cil_blockinherit *inherit = node->data;
+			cil_log(CIL_INFO, "BLOCKINHERIT: %s\n", inherit->block_str);
+			return;
+		}
+		case CIL_BLOCKABSTRACT: {
+			struct cil_blockabstract *abstract = node->data;
+			cil_log(CIL_INFO, "BLOCKABSTRACT: %s\n", abstract->block_str);
+			return;
+		}
+		case CIL_IN: {
+			struct cil_in *in = node->data;
+			cil_log(CIL_INFO, "IN: %s\n", in->block_str);
+			return;
+		}
+		case CIL_USER: {
+			struct cil_user *user = node->data;
+			cil_log(CIL_INFO, "USER: %s\n", user->datum.name);
+			return;
+		}
+		case CIL_TYPE: {
+			struct cil_type *type = node->data;
+			cil_log(CIL_INFO, "TYPE: %s\n", type->datum.name);
+			return;
+		}
+		case CIL_TYPEATTRIBUTESET: {
+			struct cil_typeattributeset *attr = node->data;
+
+			cil_log(CIL_INFO, "(TYPEATTRIBUTESET %s ", attr->attr_str);
+
+			cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_TYPEATTRIBUTE: {
+			struct cil_typeattribute *attr = node->data;
+			cil_log(CIL_INFO, "TYPEATTRIBUTE: %s\n", attr->datum.name);
+			return;
+		}
+		case CIL_ROLE: {
+			struct cil_role *role = node->data;
+			cil_log(CIL_INFO, "ROLE: %s\n", role->datum.name);
+			return;
+		}
+		case CIL_USERROLE: {
+			struct cil_userrole *userrole = node->data;
+			cil_log(CIL_INFO, "USERROLE:");
+			struct cil_symtab_datum *datum = NULL;
+
+			if (userrole->user != NULL) {
+				datum = userrole->user;
+				cil_log(CIL_INFO, " %s", datum->name);
+			} else if (userrole->user_str != NULL) {
+				cil_log(CIL_INFO, " %s", userrole->user_str);
+			}
+
+			if (userrole->role != NULL) {
+				datum = userrole->role;
+				cil_log(CIL_INFO, " %s", datum->name);
+			} else if (userrole->role_str != NULL) {
+				cil_log(CIL_INFO, " %s", userrole->role_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_USERLEVEL: {
+			struct cil_userlevel *usrlvl = node->data;
+			cil_log(CIL_INFO, "USERLEVEL:");
+
+			if (usrlvl->user_str != NULL) {
+				cil_log(CIL_INFO, " %s", usrlvl->user_str);
+			}
+
+			if (usrlvl->level != NULL) {
+				cil_log(CIL_INFO, " (");
+				cil_tree_print_level(usrlvl->level);
+				cil_log(CIL_INFO, " )");
+			} else if (usrlvl->level_str != NULL) {
+				cil_log(CIL_INFO, " %s", usrlvl->level_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_USERRANGE: {
+			struct cil_userrange *userrange = node->data;
+			cil_log(CIL_INFO, "USERRANGE:");
+
+			if (userrange->user_str != NULL) {
+				cil_log(CIL_INFO, " %s", userrange->user_str);
+			}
+
+			if (userrange->range != NULL) {
+				cil_log(CIL_INFO, " (");
+				cil_tree_print_levelrange(userrange->range);
+				cil_log(CIL_INFO, " )");
+			} else if (userrange->range_str != NULL) {
+				cil_log(CIL_INFO, " %s", userrange->range_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_USERBOUNDS: {
+			struct cil_bounds *bnds = node->data;
+			cil_log(CIL_INFO, "USERBOUNDS: user: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+			return;
+		}
+		case CIL_ROLETYPE: {
+			struct cil_roletype *roletype = node->data;
+			struct cil_symtab_datum *datum = NULL;
+			cil_log(CIL_INFO, "ROLETYPE:");
+
+			if (roletype->role != NULL) {
+				datum = roletype->role;
+				cil_log(CIL_INFO, " %s", datum->name);
+			} else if (roletype->role_str != NULL) {
+				cil_log(CIL_INFO, " %s", roletype->role_str);
+			}
+
+			if (roletype->type != NULL) {
+				datum = roletype->type;
+				cil_log(CIL_INFO, " %s", datum->name);
+			} else if (roletype->type_str != NULL) {
+				cil_log(CIL_INFO, " %s", roletype->type_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_ROLETRANSITION: {
+			struct cil_roletransition *roletrans = node->data;
+			cil_log(CIL_INFO, "ROLETRANSITION:");
+
+			if (roletrans->src != NULL) {
+				cil_log(CIL_INFO, " %s", roletrans->src->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", roletrans->src_str);
+			}
+
+			if (roletrans->tgt != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)roletrans->tgt)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", roletrans->tgt_str);
+			}
+				
+			if (roletrans->obj != NULL) {
+				cil_log(CIL_INFO, " %s", roletrans->obj->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", roletrans->obj_str);
+			}
+
+			if (roletrans->result != NULL) {
+				cil_log(CIL_INFO, " %s\n", roletrans->result->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s\n", roletrans->result_str);
+			}
+
+			return;
+		}
+		case CIL_ROLEALLOW: {
+			struct cil_roleallow *roleallow = node->data;
+			cil_log(CIL_INFO, "ROLEALLOW:");
+
+			if (roleallow->src != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->src)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", roleallow->src_str);
+			}
+
+			if (roleallow->tgt != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->tgt)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", roleallow->tgt_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_ROLEATTRIBUTESET: {
+			struct cil_roleattributeset *attr = node->data;
+
+			cil_log(CIL_INFO, "(ROLEATTRIBUTESET %s ", attr->attr_str);
+
+			cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_ROLEATTRIBUTE: {
+			struct cil_roleattribute *attr = node->data;
+			cil_log(CIL_INFO, "ROLEATTRIBUTE: %s\n", attr->datum.name);
+			return;
+		}
+		case CIL_USERATTRIBUTESET: {
+			struct cil_userattributeset *attr = node->data;
+
+			cil_log(CIL_INFO, "(USERATTRIBUTESET %s ", attr->attr_str);
+
+			cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_USERATTRIBUTE: {
+			struct cil_userattribute *attr = node->data;
+			cil_log(CIL_INFO, "USERATTRIBUTE: %s\n", attr->datum.name);
+			return;
+		}
+		case CIL_ROLEBOUNDS: {
+			struct cil_bounds *bnds = node->data;
+			cil_log(CIL_INFO, "ROLEBOUNDS: role: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+			return;
+		}
+		case CIL_CLASS: {
+			struct cil_class *cls = node->data;
+			cil_log(CIL_INFO, "CLASS: %s ", cls->datum.name);
+				
+			if (cls->common != NULL) {
+				cil_log(CIL_INFO, "inherits: %s ", cls->common->datum.name);
+			}
+			cil_log(CIL_INFO, "(");
+	
+			cil_tree_print_perms_list(node->cl_head);
+	
+			cil_log(CIL_INFO, " )");
+			return;
+		}
+		case CIL_CLASSORDER: {
+			struct cil_classorder *classorder = node->data;
+			struct cil_list_item *class;
+
+			if (classorder->class_list_str == NULL) {
+				cil_log(CIL_INFO, "CLASSORDER: ()\n");
+				return;
+			}
+
+			cil_log(CIL_INFO, "CLASSORDER: (");
+			cil_list_for_each(class, classorder->class_list_str) {
+				cil_log(CIL_INFO, " %s", (char*)class->data);
+			}
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_COMMON: {
+			struct cil_class *common = node->data;
+			cil_log(CIL_INFO, "COMMON: %s (", common->datum.name);
+		
+			cil_tree_print_perms_list(node->cl_head);
+	
+			cil_log(CIL_INFO, " )");
+			return;
+		}
+		case CIL_CLASSCOMMON: {
+			struct cil_classcommon *clscom = node->data;
+
+			cil_log(CIL_INFO, "CLASSCOMMON: class: %s, common: %s\n", clscom->class_str, clscom->common_str);
+
+			return;
+		}
+		case CIL_CLASSPERMISSION: {
+			struct cil_classpermission *cp = node->data;
+
+			cil_log(CIL_INFO, "CLASSPERMISSION: %s", cp->datum.name);
+
+			cil_log(CIL_INFO, "\n");
+
+			return;
+		}
+		case CIL_CLASSPERMISSIONSET: {
+			struct cil_classpermissionset *cps = node->data;
+
+			cil_log(CIL_INFO, "CLASSPERMISSIONSET: %s", cps->set_str);
+
+			cil_tree_print_classperms_list(cps->classperms);
+
+			cil_log(CIL_INFO, "\n");
+
+			return;
+		}
+		case CIL_MAP_CLASS: {
+			struct cil_class *cm = node->data;
+			cil_log(CIL_INFO, "MAP_CLASS: %s", cm->datum.name);
+
+			cil_log(CIL_INFO, " (");
+			cil_tree_print_perms_list(node->cl_head);
+			cil_log(CIL_INFO, " )\n");
+
+			return;
+		}
+		case CIL_MAP_PERM: {
+			struct cil_perm *cmp = node->data;
+
+			cil_log(CIL_INFO, "MAP_PERM: %s", cmp->datum.name);
+
+			if (cmp->classperms == NULL) {
+				cil_log(CIL_INFO, " perms: ()");
+				return;
+			}
+
+			cil_log(CIL_INFO, " kernel class perms: (");
+
+			cil_tree_print_classperms_list(cmp->classperms);
+
+			cil_log(CIL_INFO, " )\n");
+
+			return;
+		}
+		case CIL_CLASSMAPPING: {
+			struct cil_classmapping *mapping = node->data;
+
+			cil_log(CIL_INFO, "CLASSMAPPING: map class: %s, map perm: %s,", mapping->map_class_str, mapping->map_perm_str);
+
+			cil_log(CIL_INFO, " (");
+
+			cil_tree_print_classperms_list(mapping->classperms);
+
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_BOOL: {
+			struct cil_bool *boolean = node->data;
+			cil_log(CIL_INFO, "BOOL: %s, value: %d\n", boolean->datum.name, boolean->value);
+			return;
+		}
+		case CIL_TUNABLE: {
+			struct cil_tunable *tunable = node->data;
+			cil_log(CIL_INFO, "TUNABLE: %s, value: %d\n", tunable->datum.name, tunable->value);
+			return;
+		}
+		case CIL_BOOLEANIF: {
+			struct cil_booleanif *bif = node->data;
+
+			cil_log(CIL_INFO, "(BOOLEANIF ");
+
+			cil_tree_print_expr(bif->datum_expr, bif->str_expr);
+
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_TUNABLEIF: {
+			struct cil_tunableif *tif = node->data;
+
+			cil_log(CIL_INFO, "(TUNABLEIF ");
+
+			cil_tree_print_expr(tif->datum_expr, tif->str_expr);
+
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_CONDBLOCK: {
+			struct cil_condblock *cb = node->data;
+			if (cb->flavor == CIL_CONDTRUE) {
+				cil_log(CIL_INFO, "true\n");
+			} else if (cb->flavor == CIL_CONDFALSE) {
+				cil_log(CIL_INFO, "false\n");
+			}
+			return;
+		}
+		case CIL_ALL:
+			cil_log(CIL_INFO, "all");
+			return;
+		case CIL_AND:
+			cil_log(CIL_INFO, "&&");
+			return;
+		case CIL_OR:
+			cil_log(CIL_INFO, "|| ");
+			return;
+		case CIL_NOT:
+			cil_log(CIL_INFO, "!");
+			return;
+		case CIL_EQ:
+			cil_log(CIL_INFO, "==");
+			return;
+		case CIL_NEQ:
+			cil_log(CIL_INFO, "!=");
+			return;
+		case CIL_TYPEALIAS: {
+			struct cil_alias *alias = node->data;
+			cil_log(CIL_INFO, "TYPEALIAS: %s\n", alias->datum.name);
+			return;
+		}
+		case CIL_TYPEALIASACTUAL: {
+			struct cil_aliasactual *aliasactual = node->data;
+			cil_log(CIL_INFO, "TYPEALIASACTUAL: type: %s, alias: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+			return;
+		}
+		case CIL_TYPEBOUNDS: {
+			struct cil_bounds *bnds = node->data;
+			cil_log(CIL_INFO, "TYPEBOUNDS: type: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+			return;
+		}
+		case CIL_TYPEPERMISSIVE: {
+			struct cil_typepermissive *typeperm = node->data;
+
+			if (typeperm->type != NULL) {
+				cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", ((struct cil_symtab_datum *)typeperm->type)->name);
+			} else {
+				cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", typeperm->type_str);
+			}
+
+			return;
+		}
+		case CIL_NAMETYPETRANSITION: {
+			struct cil_nametypetransition *nametypetrans = node->data;
+			cil_log(CIL_INFO, "TYPETRANSITION:");
+
+			if (nametypetrans->src != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->src)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", nametypetrans->src_str);
+			}
+
+			if (nametypetrans->tgt != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->tgt)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", nametypetrans->tgt_str);
+			}
+
+			if (nametypetrans->obj != NULL) {
+				cil_log(CIL_INFO, " %s", nametypetrans->obj->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", nametypetrans->obj_str);
+			}
+
+			cil_log(CIL_INFO, " %s\n", nametypetrans->name_str);
+
+			if (nametypetrans->result != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->result)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", nametypetrans->result_str);
+			}
+
+			return;
+		}
+		case CIL_RANGETRANSITION: {
+			struct cil_rangetransition *rangetrans = node->data;
+			cil_log(CIL_INFO, "RANGETRANSITION:");
+
+			if (rangetrans->src != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->src)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rangetrans->src_str);
+			}
+
+			if (rangetrans->exec != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->exec)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rangetrans->exec_str);
+			}
+
+			if (rangetrans->obj != NULL) {
+				cil_log(CIL_INFO, " %s", rangetrans->obj->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", rangetrans->obj_str);
+			}
+
+			if (rangetrans->range != NULL) {
+				cil_log(CIL_INFO, " (");
+				cil_tree_print_levelrange(rangetrans->range);
+				cil_log(CIL_INFO, " )");
+			} else {
+				cil_log(CIL_INFO, " %s", rangetrans->range_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_AVRULE: {
+			struct cil_avrule *rule = node->data;
+			switch (rule->rule_kind) {
+			case CIL_AVRULE_ALLOWED:
+				cil_log(CIL_INFO, "ALLOW:");
+				break;
+			case CIL_AVRULE_AUDITALLOW:
+				cil_log(CIL_INFO, "AUDITALLOW:");
+				break;
+			case CIL_AVRULE_DONTAUDIT:
+				cil_log(CIL_INFO, "DONTAUDIT:");
+				break;
+			case CIL_AVRULE_NEVERALLOW:
+				cil_log(CIL_INFO, "NEVERALLOW:");
+				break;
+			}
+
+			if (rule->src != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->src)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rule->src_str);
+			}
+
+			if (rule->tgt != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->tgt)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rule->tgt_str);
+			}
+
+			cil_tree_print_classperms_list(rule->perms.classperms);
+
+			cil_log(CIL_INFO, "\n");
+
+			return;
+		}
+		case CIL_TYPE_RULE: {
+			struct cil_type_rule *rule = node->data;
+			switch (rule->rule_kind) {
+			case CIL_TYPE_TRANSITION:
+				cil_log(CIL_INFO, "TYPETRANSITION:");
+				break;
+			case CIL_TYPE_MEMBER:
+				cil_log(CIL_INFO, "TYPEMEMBER:");
+				break;
+			case CIL_TYPE_CHANGE:
+				cil_log(CIL_INFO, "TYPECHANGE:");
+				break;
+			}
+
+			if (rule->src != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->src)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rule->src_str);
+			}
+
+			if (rule->tgt != NULL) {
+				cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->tgt)->name);
+			} else {
+				cil_log(CIL_INFO, " %s", rule->tgt_str);
+			}
+
+			if (rule->obj != NULL) {
+				cil_log(CIL_INFO, " %s", rule->obj->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", rule->obj_str);
+			}
+
+			if (rule->result != NULL) {
+				cil_log(CIL_INFO, " %s\n", ((struct cil_symtab_datum *)rule->result)->name);
+			} else {
+				cil_log(CIL_INFO, " %s\n", rule->result_str);
+			}
+
+			return;
+		}
+		case CIL_SENS: {
+			struct cil_sens *sens = node->data;
+			cil_log(CIL_INFO, "SENSITIVITY: %s\n", sens->datum.name);
+			return;
+		}
+		case CIL_SENSALIAS: {
+			struct cil_alias *alias = node->data;
+			cil_log(CIL_INFO, "SENSITIVITYALIAS: %s\n", alias->datum.name);
+			return;
+		}
+		case CIL_SENSALIASACTUAL: {
+			struct cil_aliasactual *aliasactual = node->data;
+			cil_log(CIL_INFO, "SENSITIVITYALIAS: alias: %s, sensitivity: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+
+			return;
+		}
+		case CIL_CAT: {
+			struct cil_cat *cat = node->data;
+			cil_log(CIL_INFO, "CATEGORY: %s\n", cat->datum.name);
+			return;
+		}
+		case CIL_CATALIAS: {
+			struct cil_alias *alias = node->data;
+			cil_log(CIL_INFO, "CATEGORYALIAS: %s\n", alias->datum.name);
+			return;
+		}
+		case CIL_CATALIASACTUAL: {
+			struct cil_aliasactual *aliasactual = node->data;
+			cil_log(CIL_INFO, "CATEGORYALIAS: alias %s, category: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+			return;
+		}
+		case CIL_CATSET: {
+			struct cil_catset *catset = node->data;
+
+			cil_log(CIL_INFO, "CATSET: %s ",catset->datum.name);
+
+			cil_tree_print_cats(catset->cats);
+
+			return;
+		}
+		case CIL_CATORDER: {
+			struct cil_catorder *catorder = node->data;
+			struct cil_list_item *cat;
+
+			if (catorder->cat_list_str == NULL) {
+				cil_log(CIL_INFO, "CATORDER: ()\n");
+				return;
+			}
+
+			cil_log(CIL_INFO, "CATORDER: (");
+			cil_list_for_each(cat, catorder->cat_list_str) {
+				cil_log(CIL_INFO, " %s", (char*)cat->data);
+			}
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_SENSCAT: {
+			struct cil_senscat *senscat = node->data;
+
+			cil_log(CIL_INFO, "SENSCAT: sens:");
+
+			if (senscat->sens_str != NULL) {
+				cil_log(CIL_INFO, " %s ", senscat->sens_str);
+			} else {
+				cil_log(CIL_INFO, " [processed]");
+			}
+
+			cil_tree_print_cats(senscat->cats);
+
+			return;
+		}
+		case CIL_SENSITIVITYORDER: {
+			struct cil_sensorder *sensorder = node->data;
+			struct cil_list_item *sens;
+
+			cil_log(CIL_INFO, "SENSITIVITYORDER: (");
+
+			if (sensorder->sens_list_str != NULL) {
+				cil_list_for_each(sens, sensorder->sens_list_str) {
+					if (sens->flavor == CIL_LIST) {
+						struct cil_list_item *sub;
+						cil_log(CIL_INFO, " (");
+						cil_list_for_each(sub, (struct cil_list*)sens->data) {
+							cil_log(CIL_INFO, " %s", (char*)sub->data);
+						}
+						cil_log(CIL_INFO, " )");
+					} else {
+						cil_log(CIL_INFO, " %s", (char*)sens->data);
+					}
+				}
+			}
+
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_LEVEL: {
+			struct cil_level *level = node->data;
+			cil_log(CIL_INFO, "LEVEL %s:", level->datum.name); 
+			cil_tree_print_level(level);
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_LEVELRANGE: {
+			struct cil_levelrange *lvlrange = node->data;
+			cil_log(CIL_INFO, "LEVELRANGE %s:", lvlrange->datum.name);
+			cil_tree_print_levelrange(lvlrange);
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_CONSTRAIN: {
+			struct cil_constrain *cons = node->data;
+			cil_log(CIL_INFO, "CONSTRAIN: (");
+			cil_tree_print_constrain(cons);
+			return;
+		}
+		case CIL_MLSCONSTRAIN: {
+			struct cil_constrain *cons = node->data;
+			cil_log(CIL_INFO, "MLSCONSTRAIN: (");
+			cil_tree_print_constrain(cons);
+			return;
+		}
+		case CIL_VALIDATETRANS: {
+			struct cil_validatetrans *vt = node->data;
+
+			cil_log(CIL_INFO, "(VALIDATETRANS ");
+
+			if (vt->class != NULL) {
+				cil_log(CIL_INFO, "%s ", vt->class->datum.name);
+			} else if (vt->class_str != NULL) {
+				cil_log(CIL_INFO, "%s ", vt->class_str);
+			}
+
+			cil_tree_print_expr(vt->datum_expr, vt->str_expr);
+
+			cil_log(CIL_INFO, ")\n");
+			return;
+		}
+		case CIL_MLSVALIDATETRANS: {
+			struct cil_validatetrans *vt = node->data;
+
+			cil_log(CIL_INFO, "(MLSVALIDATETRANS ");
+
+			if (vt->class != NULL) {
+				cil_log(CIL_INFO, "%s ", vt->class->datum.name);
+			} else if (vt->class_str != NULL) {
+				cil_log(CIL_INFO, "%s ", vt->class_str);
+			}
+
+			cil_tree_print_expr(vt->datum_expr, vt->str_expr);
+
+			cil_log(CIL_INFO, ")\n");
+			return;
+		}
+		case CIL_CONTEXT: {
+			struct cil_context *context = node->data;
+			cil_log(CIL_INFO, "CONTEXT %s:", context->datum.name);
+			cil_tree_print_context(context);
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_FILECON: {
+			struct cil_filecon *filecon = node->data;
+			cil_log(CIL_INFO, "FILECON:");
+			cil_log(CIL_INFO, " %s %d", filecon->path_str, filecon->type);
+
+			if (filecon->context != NULL) {
+				cil_tree_print_context(filecon->context);
+			} else if (filecon->context_str != NULL) {
+				cil_log(CIL_INFO, " %s", filecon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+
+		}
+		case CIL_PORTCON: {
+			struct cil_portcon *portcon = node->data;
+			cil_log(CIL_INFO, "PORTCON:");
+			if (portcon->proto == CIL_PROTOCOL_UDP) {
+				cil_log(CIL_INFO, " udp");
+			} else if (portcon->proto == CIL_PROTOCOL_TCP) {
+				cil_log(CIL_INFO, " tcp");
+			} else if (portcon->proto == CIL_PROTOCOL_DCCP) {
+				cil_log(CIL_INFO, " dccp");
+			}
+			cil_log(CIL_INFO, " (%d %d)", portcon->port_low, portcon->port_high);
+
+			if (portcon->context != NULL) {
+				cil_tree_print_context(portcon->context);
+			} else if (portcon->context_str != NULL) {
+				cil_log(CIL_INFO, " %s", portcon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_NODECON: {
+			struct cil_nodecon *nodecon = node->data;
+			char buf[256];
+				
+			cil_log(CIL_INFO, "NODECON:");
+				
+			if (nodecon->addr) {
+				inet_ntop(nodecon->addr->family, &nodecon->addr->ip, buf, 256);
+				cil_log(CIL_INFO, " %s", buf);
+			}  else {
+				cil_log(CIL_INFO, " %s", nodecon->addr_str);
+			}
+
+			if (nodecon->mask) {
+				inet_ntop(nodecon->mask->family, &nodecon->mask->ip, buf, 256);
+				cil_log(CIL_INFO, " %s", buf);
+			} else {
+				cil_log(CIL_INFO, " %s", nodecon->mask_str);
+			}
+				
+			if (nodecon->context != NULL) {
+				cil_tree_print_context(nodecon->context);
+			} else if (nodecon->context_str != NULL) {
+				cil_log(CIL_INFO, " %s", nodecon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_GENFSCON: {
+			struct cil_genfscon *genfscon = node->data;
+			cil_log(CIL_INFO, "GENFSCON:");
+			cil_log(CIL_INFO, " %s %s", genfscon->fs_str, genfscon->path_str);
+
+			if (genfscon->context != NULL) {
+				cil_tree_print_context(genfscon->context);
+			} else if (genfscon->context_str != NULL) {
+				cil_log(CIL_INFO, " %s", genfscon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_NETIFCON: {
+			struct cil_netifcon *netifcon = node->data;
+			cil_log(CIL_INFO, "NETIFCON %s", netifcon->interface_str);
+
+			if (netifcon->if_context != NULL) {
+				cil_tree_print_context(netifcon->if_context);
+			} else if (netifcon->if_context_str != NULL) {
+				cil_log(CIL_INFO, " %s", netifcon->if_context_str);
+			}
+
+			if (netifcon->packet_context != NULL) {
+				cil_tree_print_context(netifcon->packet_context);
+			} else if (netifcon->packet_context_str != NULL) {
+				cil_log(CIL_INFO, " %s", netifcon->packet_context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_PIRQCON: {
+			struct cil_pirqcon *pirqcon = node->data;
+
+			cil_log(CIL_INFO, "PIRQCON %d", pirqcon->pirq);
+			if (pirqcon->context != NULL) {
+				cil_tree_print_context(pirqcon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", pirqcon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_IOMEMCON: {
+			struct cil_iomemcon *iomemcon = node->data;
+
+			cil_log(CIL_INFO, "IOMEMCON ( %"PRId64" %"PRId64" )", iomemcon->iomem_low, iomemcon->iomem_high);
+			if (iomemcon->context != NULL) {
+				cil_tree_print_context(iomemcon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", iomemcon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_IOPORTCON: {
+			struct cil_ioportcon *ioportcon = node->data;
+
+			cil_log(CIL_INFO, "IOPORTCON ( %d %d )", ioportcon->ioport_low, ioportcon->ioport_high);
+			if (ioportcon->context != NULL) {
+				cil_tree_print_context(ioportcon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", ioportcon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_PCIDEVICECON: {
+			struct cil_pcidevicecon *pcidevicecon = node->data;
+
+			cil_log(CIL_INFO, "PCIDEVICECON %d", pcidevicecon->dev);
+			if (pcidevicecon->context != NULL) {
+				cil_tree_print_context(pcidevicecon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", pcidevicecon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_DEVICETREECON: {
+			struct cil_devicetreecon *devicetreecon = node->data;
+
+			cil_log(CIL_INFO, "DEVICETREECON %s", devicetreecon->path);
+			if (devicetreecon->context != NULL) {
+				cil_tree_print_context(devicetreecon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", devicetreecon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_FSUSE: {
+			struct cil_fsuse *fsuse = node->data;
+			cil_log(CIL_INFO, "FSUSE: ");
+
+			if (fsuse->type == CIL_FSUSE_XATTR) {
+				cil_log(CIL_INFO, "xattr ");
+			} else if (fsuse->type == CIL_FSUSE_TASK) {
+				cil_log(CIL_INFO, "task ");
+			} else if (fsuse->type == CIL_FSUSE_TRANS) {
+				cil_log(CIL_INFO, "trans ");
+			} else {
+				cil_log(CIL_INFO, "unknown ");
+			}
+
+			cil_log(CIL_INFO, "%s ", fsuse->fs_str);
+
+			if (fsuse->context != NULL) {
+				cil_tree_print_context(fsuse->context);
+			} else {
+				cil_log(CIL_INFO, " %s", fsuse->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_SID: {
+			struct cil_sid *sid = node->data;
+			cil_log(CIL_INFO, "SID: %s\n", sid->datum.name);
+			return;
+		}
+		case CIL_SIDCONTEXT: {
+			struct cil_sidcontext *sidcon = node->data;
+			cil_log(CIL_INFO, "SIDCONTEXT: %s", sidcon->sid_str);
+
+			if (sidcon->context != NULL) {
+				cil_tree_print_context(sidcon->context);
+			} else {
+				cil_log(CIL_INFO, " %s", sidcon->context_str);
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
+		case CIL_SIDORDER: {
+			struct cil_sidorder *sidorder = node->data;
+			struct cil_list_item *sid;
+
+			if (sidorder->sid_list_str == NULL) {
+				cil_log(CIL_INFO, "SIDORDER: ()\n");
+				return;
+			}
+
+			cil_log(CIL_INFO, "SIDORDER: (");
+			cil_list_for_each(sid, sidorder->sid_list_str) {
+				cil_log(CIL_INFO, " %s", (char*)sid->data);
+			}
+			cil_log(CIL_INFO, " )\n");
+			return;
+		}
+		case CIL_POLICYCAP: {
+			struct cil_policycap *polcap = node->data;
+			cil_log(CIL_INFO, "POLICYCAP: %s\n", polcap->datum.name);
+			return;
+		}
+		case CIL_MACRO: {
+			struct cil_macro *macro = node->data;
+			cil_log(CIL_INFO, "MACRO %s:", macro->datum.name);
+
+			if (macro->params != NULL && macro->params->head != NULL) {
+				struct cil_list_item *curr_param;
+				cil_log(CIL_INFO, " parameters: (");
+				cil_list_for_each(curr_param, macro->params) {
+					cil_log(CIL_INFO, " flavor: %d, string: %s;", ((struct cil_param*)curr_param->data)->flavor, ((struct cil_param*)curr_param->data)->str);
+
+				}
+				cil_log(CIL_INFO, " )");
+			}
+			cil_log(CIL_INFO, "\n");
+
+			return;
+		}
+		case CIL_CALL: {
+			struct cil_call *call = node->data;
+			cil_log(CIL_INFO, "CALL: macro name:");
+
+			if (call->macro != NULL) {
+				cil_log(CIL_INFO, " %s", call->macro->datum.name);
+			} else {
+				cil_log(CIL_INFO, " %s", call->macro_str);
+			}
+
+			if (call->args != NULL) {
+				cil_log(CIL_INFO, ", args: ( ");
+				struct cil_list_item *item;
+				cil_list_for_each(item, call->args) {
+					struct cil_symtab_datum *datum = ((struct cil_args*)item->data)->arg;
+					if (datum != NULL) {
+						if (datum->nodes != NULL && datum->nodes->head != NULL) {
+							cil_tree_print_node((struct cil_tree_node*)datum->nodes->head->data);
+						}
+					} else if (((struct cil_args*)item->data)->arg_str != NULL) {
+						switch (item->flavor) {
+						case CIL_TYPE: cil_log(CIL_INFO, "type:"); break;
+						case CIL_USER: cil_log(CIL_INFO, "user:"); break;
+						case CIL_ROLE: cil_log(CIL_INFO, "role:"); break;
+						case CIL_SENS: cil_log(CIL_INFO, "sensitivity:"); break;
+						case CIL_CAT: cil_log(CIL_INFO, "category:"); break;
+						case CIL_CATSET: cil_log(CIL_INFO, "categoryset:"); break;
+						case CIL_LEVEL: cil_log(CIL_INFO, "level:"); break;
+						case CIL_CLASS: cil_log(CIL_INFO, "class:"); break;
+						default: break;
+						}
+						cil_log(CIL_INFO, "%s ", ((struct cil_args*)item->data)->arg_str);
+					}
+				}
+				cil_log(CIL_INFO, ")");
+			}
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}	
+		case CIL_OPTIONAL: {
+			struct cil_optional *optional = node->data;
+			cil_log(CIL_INFO, "OPTIONAL: %s\n", optional->datum.name);
+			return;
+		}
+		case CIL_IPADDR: {
+			struct cil_ipaddr *ipaddr = node->data;
+			char buf[256];
+
+			inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256);
+			cil_log(CIL_INFO, "IPADDR %s: %s\n", ipaddr->datum.name, buf);
+
+			break;
+		}
+		default : {
+			cil_log(CIL_INFO, "CIL FLAVOR: %d\n", node->flavor);
+			return;
+		}
+		}
+	}
+}
+
+void cil_tree_print(struct cil_tree_node *tree, uint32_t depth)
+{
+	struct cil_tree_node *current = NULL;
+	current = tree;
+	uint32_t x = 0;
+
+	if (current != NULL) {
+		if (current->cl_head == NULL) {
+			if (current->flavor == CIL_NODE) {
+				if (current->parent->cl_head == current) {
+					cil_log(CIL_INFO, "%s", (char*)current->data);
+				} else {
+					cil_log(CIL_INFO, " %s", (char*)current->data);
+				}
+			} else if (current->flavor != CIL_PERM) {
+				for (x = 0; x<depth; x++) {
+					cil_log(CIL_INFO, "\t");
+				}
+				cil_tree_print_node(current);
+			}
+		} else {
+			if (current->parent != NULL) {
+				cil_log(CIL_INFO, "\n");
+				for (x = 0; x<depth; x++) {
+					cil_log(CIL_INFO, "\t");
+				}
+				cil_log(CIL_INFO, "(");
+
+				if (current->flavor != CIL_NODE) {
+					cil_tree_print_node(current);
+				}
+			}
+			cil_tree_print(current->cl_head, depth + 1);
+		}
+
+		if (current->next == NULL) {
+			if ((current->parent != NULL) && (current->parent->cl_tail == current) && (current->parent->parent != NULL)) {
+				if (current->flavor == CIL_PERM) {
+					cil_log(CIL_INFO, ")\n");
+				} else if (current->flavor != CIL_NODE) {
+					for (x = 0; x<depth-1; x++) {
+						cil_log(CIL_INFO, "\t");
+					}
+					cil_log(CIL_INFO, ")\n");
+				} else {
+					cil_log(CIL_INFO, ")");
+				}
+			}
+
+			if ((current->parent != NULL) && (current->parent->parent == NULL))
+				cil_log(CIL_INFO, "\n\n");
+		} else {
+			cil_tree_print(current->next, depth);
+		}
+	} else {
+		cil_log(CIL_INFO, "Tree is NULL\n");
+	}
+}
diff --git a/libsepol/cil/src/cil_tree.h b/libsepol/cil/src/cil_tree.h
new file mode 100644
index 0000000..aeded56
--- /dev/null
+++ b/libsepol/cil/src/cil_tree.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_TREE_H_
+#define CIL_TREE_H_
+
+#include <stdint.h>
+
+#include "cil_flavor.h"
+#include "cil_list.h"
+
+struct cil_tree {
+	struct cil_tree_node *root;
+};
+
+struct cil_tree_node {
+	struct cil_tree_node *parent;
+	struct cil_tree_node *cl_head;		//Head of child_list
+	struct cil_tree_node *cl_tail;		//Tail of child_list
+	struct cil_tree_node *next;		//Each element in the list points to the next element
+	enum cil_flavor flavor;
+	uint32_t line;
+	uint32_t hll_line;
+	void *data;
+};
+
+struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil);
+char *cil_tree_get_cil_path(struct cil_tree_node *node);
+__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...);
+
+int cil_tree_init(struct cil_tree **tree);
+void cil_tree_destroy(struct cil_tree **tree);
+void cil_tree_subtree_destroy(struct cil_tree_node *node);
+void cil_tree_children_destroy(struct cil_tree_node *node);
+
+void cil_tree_node_init(struct cil_tree_node **node);
+void cil_tree_node_destroy(struct cil_tree_node **node);
+
+void cil_tree_print(struct cil_tree_node *tree, uint32_t depth);
+
+//finished values
+#define CIL_TREE_SKIP_NOTHING	0
+#define CIL_TREE_SKIP_NEXT	1
+#define CIL_TREE_SKIP_HEAD	2
+#define CIL_TREE_SKIP_ALL	(CIL_TREE_SKIP_NOTHING | CIL_TREE_SKIP_NEXT | CIL_TREE_SKIP_HEAD)
+int cil_tree_walk(struct cil_tree_node *start_node, int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), int (*first_child)(struct cil_tree_node *node, void *extra_args), int (*last_child)(struct cil_tree_node *node, void *extra_args), void *extra_args);
+
+#endif /* CIL_TREE_H_ */
+
diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c
new file mode 100644
index 0000000..038f77a
--- /dev/null
+++ b/libsepol/cil/src/cil_verify.c
@@ -0,0 +1,1644 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <sepol/policydb/polcaps.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_find.h"
+
+#include "cil_verify.h"
+
+int __cil_verify_name(const char *name)
+{
+	int rc = SEPOL_ERR;
+	int len = strlen(name);
+	int i = 0;
+
+	if (len >= CIL_MAX_NAME_LENGTH) {
+		cil_log(CIL_ERR, "Name length greater than max name length of %d", 
+			CIL_MAX_NAME_LENGTH);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (!isalpha(name[0])) {
+			cil_log(CIL_ERR, "First character in %s is not a letter\n", name);
+			goto exit;
+	}
+
+	for (i = 1; i < len; i++) {
+		if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') {
+			cil_log(CIL_ERR, "Invalid character \"%c\" in %s\n", name[i], name);
+			goto exit;
+		}
+	}
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Invalid name\n");
+	return rc;
+}
+
+int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len)
+{
+	int rc = SEPOL_ERR;
+	int num_extras = 0;
+	struct cil_tree_node *c = parse_current;
+	int i = 0;
+	while (i < len) {
+		if ((s[i] & CIL_SYN_END) && c == NULL) {
+			break;
+		}
+
+		if (s[i] & CIL_SYN_N_LISTS || s[i] & CIL_SYN_N_STRINGS) {
+			if (c == NULL) {
+				if (num_extras > 0) {
+					i++;
+					continue;
+				} else {
+					goto exit;
+				}
+			} else if ((s[i] & CIL_SYN_N_LISTS) && (c->data == NULL && c->cl_head != NULL)) {
+				c = c->next;
+				num_extras++;
+				continue;
+			} else if ((s[i] & CIL_SYN_N_STRINGS) && (c->data != NULL && c->cl_head == NULL)) {
+				c = c->next;
+				num_extras++;
+				continue;
+			}
+		}
+
+		if (c == NULL) {
+			goto exit;
+		}
+
+		if (s[i] & CIL_SYN_STRING) {
+			if (c->data != NULL && c->cl_head == NULL) {
+				c = c->next;
+				i++;
+				continue;
+			}
+		}
+
+		if (s[i] & CIL_SYN_LIST) {
+			if (c->data == NULL && c->cl_head != NULL) {
+				c = c->next;
+				i++;
+				continue;
+			}
+		}
+
+		if (s[i] & CIL_SYN_EMPTY_LIST) {
+			if (c->data == NULL && c->cl_head == NULL) {
+				c = c->next;
+				i++;
+				continue;
+			}
+		}
+		goto exit;
+	}
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Invalid syntax\n");
+	return rc;
+}
+
+int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor)
+{
+	int rc;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	switch (op) {
+	case CIL_NOT:
+		syntax[2] = CIL_SYN_END;
+		syntax_len = 3;
+		break;
+	case CIL_AND:
+	case CIL_OR:
+	case CIL_XOR:
+		break;
+	case CIL_EQ:
+	case CIL_NEQ:
+		if (expr_flavor != CIL_BOOL && expr_flavor != CIL_TUNABLE ) {
+			cil_log(CIL_ERR,"Invalid operator (%s) for set expression\n", (char*)current->data);
+			goto exit;
+		}
+		break;
+	case CIL_ALL:
+		if (expr_flavor == CIL_BOOL || expr_flavor == CIL_TUNABLE) {
+			cil_log(CIL_ERR,"Invalid operator (%s) for boolean or tunable expression\n", (char*)current->data);
+			goto exit;
+		}
+		syntax[1] = CIL_SYN_END;
+		syntax_len = 2;
+		break;
+	case CIL_RANGE:
+		if (expr_flavor != CIL_CAT && expr_flavor != CIL_PERMISSIONX) {
+			cil_log(CIL_ERR,"Operator (%s) only valid for catset and permissionx expression\n", (char*)current->data);
+			goto exit;
+		}
+		syntax[1] = CIL_SYN_STRING;
+		syntax[2] = CIL_SYN_STRING;
+		break;
+	case CIL_NONE: /* String or List */
+		syntax[0] = CIL_SYN_N_STRINGS | CIL_SYN_N_LISTS;
+		syntax[1] = CIL_SYN_END;
+		syntax_len = 2;
+		break;
+	default:
+		cil_log(CIL_ERR,"Unexpected value (%s) for expression operator\n", (char*)current->data);
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor)
+{
+	if (r_flavor == CIL_STRING || r_flavor == CIL_LIST) {
+		if (l_flavor == CIL_CONS_L1 || l_flavor == CIL_CONS_L2 || l_flavor == CIL_CONS_H1 || l_flavor == CIL_CONS_H2 ) {
+			cil_log(CIL_ERR, "l1, l2, h1, and h2 cannot be used on the left side with a string or list on the right side\n");
+			goto exit;
+		} else if (l_flavor == CIL_CONS_U3 || l_flavor == CIL_CONS_R3 || l_flavor == CIL_CONS_T3) {
+			if (expr_flavor != CIL_MLSVALIDATETRANS) {
+				cil_log(CIL_ERR, "u3, r3, and t3 can only be used with mlsvalidatetrans rules\n");
+				goto exit;
+			}
+		}
+	} else {
+		if (r_flavor == CIL_CONS_U2) {
+			if (op != CIL_EQ && op != CIL_NEQ) {
+				cil_log(CIL_ERR, "u2 on the right side must be used with eq or neq as the operator\n");
+				goto exit;
+			} else if (l_flavor != CIL_CONS_U1) {
+				cil_log(CIL_ERR, "u2 on the right side must be used with u1 on the left\n");
+				goto exit;
+			}
+		} else if (r_flavor == CIL_CONS_R2) {
+			if (l_flavor != CIL_CONS_R1) {
+				cil_log(CIL_ERR, "r2 on the right side must be used with r1 on the left\n");
+				goto exit;
+			}
+		} else if (r_flavor == CIL_CONS_T2) {
+			if (op != CIL_EQ && op != CIL_NEQ) {
+				cil_log(CIL_ERR, "t2 on the right side must be used with eq or neq as the operator\n");
+				goto exit;
+			} else if (l_flavor != CIL_CONS_T1) {
+				cil_log(CIL_ERR, "t2 on the right side must be used with t1 on the left\n");
+				goto exit;
+			}
+		} else if (r_flavor == CIL_CONS_L2) {
+			if (l_flavor != CIL_CONS_L1 && l_flavor != CIL_CONS_H1) {
+				cil_log(CIL_ERR, "l2 on the right side must be used with l1 or h1 on the left\n");
+				goto exit;
+			}
+		} else if (r_flavor == CIL_CONS_H2) {
+			if (l_flavor != CIL_CONS_L1 && l_flavor != CIL_CONS_L2 && l_flavor != CIL_CONS_H1 ) {
+				cil_log(CIL_ERR, "h2 on the right side must be used with l1, l2, or h1 on the left\n");
+				goto exit;
+			}
+		} else if (r_flavor == CIL_CONS_H1) {
+			if (l_flavor != CIL_CONS_L1) {
+				cil_log(CIL_ERR, "h1 on the right side must be used with l1 on the left\n");
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op)
+{
+	int rc;
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_END,
+		CIL_SYN_END,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+	switch (op) {
+	case CIL_NOT:
+		syntax[1] = CIL_SYN_LIST;
+		syntax_len--;
+		break;
+	case CIL_AND:
+	case CIL_OR:
+		syntax[1] = CIL_SYN_LIST;
+		syntax[2] = CIL_SYN_LIST;
+		break;
+	case CIL_EQ:
+	case CIL_NEQ:
+		syntax[1] = CIL_SYN_STRING;
+		syntax[2] = CIL_SYN_STRING | CIL_SYN_LIST;
+		break;
+	case CIL_CONS_DOM:
+	case CIL_CONS_DOMBY:
+	case CIL_CONS_INCOMP:
+		syntax[1] = CIL_SYN_STRING;
+		syntax[2] = CIL_SYN_STRING;
+		break;
+	default:
+		cil_log(CIL_ERR, "Invalid operator (%s) for constraint expression\n", (char*)current->data);
+		goto exit;
+	}
+
+	rc = __cil_verify_syntax(current, syntax, syntax_len);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Invalid constraint syntax\n");
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return SEPOL_ERR;
+}
+
+int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list)
+{
+	struct cil_list_item *i;
+
+	cil_list_for_each(i, datum_list) {
+		if (i->flavor == CIL_DATUM) {
+			struct cil_symtab_datum *d = i->data;
+			if (d == datum) {
+				cil_log(CIL_ERR,"Self-reference found for %s\n",datum->name);
+				return SEPOL_ERR;
+			}
+		} else if (i->flavor == CIL_LIST) {
+			int rc = cil_verify_no_self_reference(datum, i->data);
+			if (rc != SEPOL_OK) {
+				return SEPOL_ERR;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_verify_ranges(struct cil_list *list)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+	struct cil_list_item *range = NULL;
+
+	if (list == NULL || list->head == NULL) {
+		goto exit;
+	}
+
+	cil_list_for_each(curr, list) {
+		/* range */
+		if (curr->flavor == CIL_LIST) {
+			range = ((struct cil_list*)curr->data)->head;
+			if (range == NULL || range->next == NULL || range->next->next != NULL) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR,"Invalid Range syntax\n");
+	return rc;
+}
+
+struct cil_args_verify_order {
+	uint32_t *flavor;
+};
+
+int __cil_verify_ordered_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+	struct cil_args_verify_order *args = extra_args;
+	uint32_t *flavor = args->flavor;
+
+	if (node->flavor == *flavor) {
+		if (node->flavor == CIL_SID) {
+			struct cil_sid *sid = node->data;
+			if (sid->ordered == CIL_FALSE) {
+				cil_tree_log(node, CIL_ERR, "SID %s not in sidorder statement", sid->datum.name);
+				return SEPOL_ERR;
+			}
+		} else if (node->flavor == CIL_CLASS) {
+			struct cil_class *class = node->data;
+			if (class->ordered == CIL_FALSE) {
+				cil_tree_log(node, CIL_ERR, "Class %s not in classorder statement", class->datum.name);
+				return SEPOL_ERR;
+			}
+		} else if (node->flavor == CIL_CAT) {
+			struct cil_cat *cat = node->data;
+			if (cat->ordered == CIL_FALSE) {
+				cil_tree_log(node, CIL_ERR, "Category %s not in categoryorder statement", cat->datum.name);
+				return SEPOL_ERR;
+			}
+		} else if (node->flavor == CIL_SENS) {
+			struct cil_sens *sens = node->data;
+			if (sens->ordered == CIL_FALSE) {
+				cil_tree_log(node, CIL_ERR, "Sensitivity %s not in sensitivityorder statement", sens->datum.name);
+				return SEPOL_ERR;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor)
+{
+	struct cil_args_verify_order extra_args;
+	int rc = SEPOL_ERR;
+
+	extra_args.flavor = &flavor;
+
+	rc = cil_tree_walk(current, __cil_verify_ordered_node_helper, NULL, NULL, &extra_args);
+
+	return rc;
+}
+
+int __cil_verify_initsids(struct cil_list *sids)
+{
+	int rc = SEPOL_OK;
+	struct cil_list_item *i;
+
+	if (sids->head == NULL) {
+		cil_log(CIL_ERR, "At least one initial sid must be defined in the policy\n");
+		return SEPOL_ERR;
+	}
+
+	cil_list_for_each(i, sids) {
+		struct cil_sid *sid = i->data;
+		if (sid->context == NULL) {
+			struct cil_tree_node *node = sid->datum.nodes->head->data;
+			cil_tree_log(node, CIL_ERR, "No context assigned to SID %s declared",sid->datum.name);
+			rc = SEPOL_ERR;
+		}
+	}
+
+	return rc;
+}
+
+int __cil_is_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats)
+{
+	struct cil_list_item *i;
+
+	cil_list_for_each(i, cats->datum_expr) {
+		struct cil_cat *c = i->data;
+		if (c == cat) {
+			return CIL_TRUE;
+		}
+	}
+
+	return CIL_FALSE;
+}
+
+
+int __cil_verify_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats)
+{
+	if (__cil_is_cat_in_cats(cat, cats) != CIL_TRUE) {
+		cil_log(CIL_ERR, "Failed to find category %s in category list\n", cat->datum.name);
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_verify_cats_associated_with_sens(struct cil_sens *sens, struct cil_cats *cats)
+{
+	int rc = SEPOL_OK;
+	struct cil_list_item *i, *j;
+
+	if (!cats) {
+		return SEPOL_OK;
+	}
+
+	if (!sens->cats_list) {
+		cil_log(CIL_ERR, "No categories can be used with sensitivity %s\n", sens->datum.name);
+		return SEPOL_ERR;
+	}
+
+	cil_list_for_each(i, cats->datum_expr) {
+		struct cil_cat *cat = i->data;
+		int ok = CIL_FALSE;
+		cil_list_for_each(j, sens->cats_list) {
+			if (__cil_is_cat_in_cats(cat, j->data) == CIL_TRUE) {
+				ok = CIL_TRUE;
+				break;
+			}
+		}
+
+		if (ok != CIL_TRUE) {
+			cil_log(CIL_ERR, "Category %s cannot be used with sensitivity %s\n", 
+					cat->datum.name, sens->datum.name);
+			rc = SEPOL_ERR;
+		}
+	}
+
+	return rc;
+}
+
+int __cil_verify_levelrange_sensitivity(struct cil_db *db, struct cil_sens *low, struct cil_sens *high)
+{
+	struct cil_list_item *curr;
+	int found = CIL_FALSE;
+	int rc = SEPOL_ERR;
+
+	cil_list_for_each(curr, db->sensitivityorder) {
+		if (curr->data == low) {
+			found = CIL_TRUE;
+		}
+
+		if ((found == CIL_TRUE) && (curr->data == high)) {
+			break;
+		}
+	}
+
+	if (found != CIL_TRUE || curr == NULL) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Sensitivity %s does not dominate %s\n", 
+		high->datum.name, low->datum.name);
+	return rc;
+
+}
+
+int __cil_verify_levelrange_cats(struct cil_cats *low, struct cil_cats *high)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *item;
+
+	if (low == NULL || (low == NULL && high == NULL)) {
+		return SEPOL_OK;
+	}
+
+	if (high == NULL) {
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	cil_list_for_each(item, low->datum_expr) {
+		rc = __cil_verify_cat_in_cats(item->data, high);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_log(CIL_ERR, "Low level category set must be a subset of the high level category set\n");
+	return rc;
+}
+
+int __cil_verify_levelrange(struct cil_db *db, struct cil_levelrange *lr)
+{
+	int rc = SEPOL_ERR;
+
+	rc = __cil_verify_levelrange_sensitivity(db, lr->low->sens, lr->high->sens);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_verify_levelrange_cats(lr->low->cats, lr->high->cats);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	rc = __cil_verify_cats_associated_with_sens(lr->low->sens, lr->low->cats);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Low level sensitivity and categories are not associated\n");
+		goto exit;
+	}
+
+	rc = __cil_verify_cats_associated_with_sens(lr->high->sens, lr->high->cats);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "High level sensitivity and categories are not associated\n");
+		goto exit;
+	}
+	
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_verify_named_levelrange(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_levelrange *lr = node->data;
+
+	rc = __cil_verify_levelrange(db, lr);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid named range");
+	return rc;
+}
+
+static int __cil_verify_user_pre_eval(struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_user *user = node->data;
+
+	if (user->dftlevel == NULL) {
+		cil_log(CIL_ERR, "User %s does not have a default level\n", user->datum.name);
+		goto exit;
+	} else if (user->range == NULL) {
+		cil_log(CIL_ERR, "User %s does not have a level range\n", user->datum.name);
+		goto exit;
+	} else if (user->bounds != NULL) {
+		int steps = 0;
+		int limit = 2;
+		struct cil_user *u1 = user;
+		struct cil_user *u2 = user->bounds;
+
+		while (u2 != NULL) {
+			if (u1 == u2) {
+				cil_log(CIL_ERR, "Circular bounds found for user %s\n", u1->datum.name);
+				goto exit;
+			}
+
+			if (steps == limit) {
+				steps = 0;
+				limit *= 2;
+				u1 = u2;
+			}
+
+			u2 = u2->bounds;
+			steps++;
+		}
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid user");
+	return rc;
+}
+
+static int __cil_verify_user_post_eval(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_user *user = node->data;
+
+	/* Verify user range only if anonymous */
+	if (user->range->datum.name == NULL) {
+		rc = __cil_verify_levelrange(db, user->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid user");
+	return rc;
+}
+
+int __cil_verify_role(struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_role *role = node->data;
+	int steps = 0;
+	int limit = 2;
+	struct cil_role *r1 = role;
+	struct cil_role *r2 = role->bounds;
+
+	while (r2 != NULL) {
+		if (r1 == r2) {
+			cil_log(CIL_ERR, "Circular bounds found for role %s\n", r1->datum.name);
+			goto exit;
+		}
+
+		if (steps == limit) {
+			steps = 0;
+			limit *= 2;
+			r1 = r2;
+		}
+
+		r2 = r2->bounds;
+		steps++;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid role");
+	return rc;
+}
+
+int __cil_verify_type(struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_type *type = node->data;
+	int steps = 0;
+	int limit = 2;
+	struct cil_type *t1 = type;
+	struct cil_type *t2 = type->bounds;
+
+	while (t2 != NULL) {
+		if (t1 == t2) {
+			cil_log(CIL_ERR, "Circular bounds found for type %s\n", t1->datum.name);
+			goto exit;
+		}
+
+		if (steps == limit) {
+			steps = 0;
+			limit *= 2;
+			t1 = t2;
+		}
+
+		t2 = t2->bounds;
+		steps++;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid type");
+	return rc;
+}
+
+int __cil_verify_context(struct cil_db *db, struct cil_context *ctx)
+{
+	int rc = SEPOL_ERR;
+	struct cil_user *user = ctx->user;
+	struct cil_role *role = ctx->role;
+	struct cil_type *type = ctx->type;
+	struct cil_level *user_low = user->range->low;
+	struct cil_level *user_high = user->range->high;
+	struct cil_level *ctx_low = ctx->range->low;
+	struct cil_level *ctx_high = ctx->range->high;
+	struct cil_list *sensitivityorder = db->sensitivityorder;
+	struct cil_list_item *curr;
+	int found = CIL_FALSE;
+
+	if (user->roles != NULL) {
+		if (!ebitmap_get_bit(user->roles, role->value)) {
+			cil_log(CIL_ERR, "Role %s is invalid for user %s\n", ctx->role_str, ctx->user_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		cil_log(CIL_ERR, "No roles given to the user %s\n", ctx->user_str);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	if (role->types != NULL) {
+		if (!ebitmap_get_bit(role->types, type->value)) {
+			cil_log(CIL_ERR, "Type %s is invalid for role %s\n", ctx->type_str, ctx->role_str);
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		cil_log(CIL_ERR, "No types associated with role %s\n", ctx->role_str);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	/* Verify range only when anonymous */
+	if (ctx->range->datum.name == NULL) {
+		rc = __cil_verify_levelrange(db, ctx->range);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	for (curr = sensitivityorder->head; curr != NULL; curr = curr->next) {
+		struct cil_sens *sens = curr->data;
+
+		if (found == CIL_FALSE) {
+			if (sens == user_low->sens) {
+				found = CIL_TRUE;
+			} else if (sens == ctx_low->sens) {
+				cil_log(CIL_ERR, "Range %s is invalid for user %s\n", 
+					ctx->range_str, ctx->user_str);
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+
+		if (found == CIL_TRUE) {
+			if (sens == ctx_high->sens) {
+				break;
+			} else if (sens == user_high->sens) {
+				cil_log(CIL_ERR, "Range %s is invalid for user %s\n", 
+					ctx->range_str, ctx->user_str);
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_log(CIL_ERR, "Invalid context\n");
+	return rc;
+}
+
+int __cil_verify_named_context(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_context *ctx = node->data;
+
+	rc = __cil_verify_context(db, ctx);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid named context");
+	return rc;
+}
+
+int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *symtab)
+{
+
+	int rc = SEPOL_ERR;
+	struct cil_type_rule *typerule = NULL;
+	struct cil_roletransition *roletrans = NULL;
+	struct cil_complex_symtab_key ckey;
+
+	switch (node->flavor) {
+	case CIL_ROLETRANSITION: {
+		roletrans = node->data;
+		ckey.key1 = (intptr_t)roletrans->src;
+		ckey.key2 = (intptr_t)roletrans->tgt;
+		ckey.key3 = (intptr_t)roletrans->obj;
+		ckey.key4 = CIL_ROLETRANSITION;
+		break;
+	}
+	case CIL_TYPE_RULE: {
+		typerule = node->data;
+		ckey.key1 = (intptr_t)typerule->src;
+		ckey.key2 = (intptr_t)typerule->tgt;
+		ckey.key3 = (intptr_t)typerule->obj;
+		ckey.key4 = (intptr_t)typerule->rule_kind;
+		break;
+	}
+	default:
+		break;
+	}
+
+
+	rc = cil_complex_symtab_insert(symtab, &ckey, NULL);
+	if (rc == SEPOL_EEXIST) {
+		struct cil_complex_symtab_datum *datum = NULL;
+		cil_complex_symtab_search(symtab, &ckey, &datum);
+		if (datum == NULL) {
+			cil_tree_log(node, CIL_ERR, "Duplicate rule defined");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid rule");
+	return rc;
+}
+
+int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_tree_node *rule_node = node;
+	struct cil_booleanif *bif = node->parent->parent->data;
+
+	switch (rule_node->flavor) {
+	case CIL_AVRULE: {
+		struct cil_avrule *avrule = NULL;
+		avrule = rule_node->data;
+		if (avrule->rule_kind == CIL_AVRULE_NEVERALLOW) {
+			if (bif->preserved_tunable) {
+				cil_tree_log(node, CIL_ERR, "Neverallow found in tunableif block (treated as a booleanif due to preserve-tunables)");
+			} else {
+				cil_tree_log(node, CIL_ERR, "Neverallow found in booleanif block");
+			}
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+		break;
+	}
+	case CIL_TYPE_RULE: /*
+	struct cil_type_rule *typerule = NULL;
+	struct cil_tree_node *temp_node = NULL;
+	struct cil_complex_symtab *symtab = extra_args;
+	struct cil_complex_symtab_key ckey;
+	struct cil_complex_symtab_datum datum;
+		typerule = rule_node->data;
+
+		ckey.key1 = (intptr_t)typerule->src;
+		ckey.key2 = (intptr_t)typerule->tgt;
+		ckey.key3 = (intptr_t)typerule->obj;
+		ckey.key4 = (intptr_t)typerule->rule_kind;
+
+		datum.data = node;
+
+		rc = cil_complex_symtab_insert(symtab, &ckey, &datum);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
+		for (temp_node = rule_node->next;
+			temp_node != NULL;
+			temp_node = temp_node->next) {
+
+			if (temp_node->flavor == CIL_TYPE_RULE) {
+				typerule = temp_node->data;
+				if ((intptr_t)typerule->src == ckey.key1 &&
+					(intptr_t)typerule->tgt == ckey.key2 &&
+					(intptr_t)typerule->obj == ckey.key3 &&
+					(intptr_t)typerule->rule_kind == ckey.key4) {
+					cil_log(CIL_ERR, "Duplicate type rule found (line: %d)\n", node->line);
+					rc = SEPOL_ERR;
+					goto exit;
+				}
+			}
+		}
+		break;*/
+
+		//TODO Fix duplicate type_rule detection
+		break;
+	case CIL_CALL:
+		//Fall through to check content of call
+		break;
+	case CIL_TUNABLEIF:
+		//Fall through
+		break;
+	case CIL_NAMETYPETRANSITION:
+		/* While type transitions with file component are not allowed in
+		   booleanif statements if they don't have "*" as the file. We
+		   can't check that here. Or at least we won't right now. */
+		break;
+	default: {
+		const char * flavor = cil_node_to_string(node);
+		if (bif->preserved_tunable) {
+			cil_tree_log(node, CIL_ERR, "Invalid %s statement in tunableif (treated as a booleanif due to preserve-tunables)", flavor);
+		} else {
+			cil_tree_log(node, CIL_ERR, "Invalid %s statement in booleanif", flavor);
+		}
+		goto exit;
+	}
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
+int __cil_verify_booleanif(struct cil_tree_node *node, struct cil_complex_symtab *symtab)
+{
+	int rc = SEPOL_ERR;
+	struct cil_booleanif *bif = (struct cil_booleanif*)node->data;
+	struct cil_tree_node *cond_block = node->cl_head;
+
+	while (cond_block != NULL) {
+		rc = cil_tree_walk(cond_block, __cil_verify_booleanif_helper, NULL, NULL, symtab);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		cond_block = cond_block->next;
+	}
+
+	return SEPOL_OK;
+exit:
+	if (bif->preserved_tunable) {
+		cil_tree_log(node, CIL_ERR, "Invalid tunableif (treated as a booleanif due to preserve-tunables)");
+	} else {
+		cil_tree_log(node, CIL_ERR, "Invalid booleanif");
+	}
+	return rc;
+}
+
+int __cil_verify_netifcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_netifcon *netif = node->data;
+	struct cil_context *if_ctx = netif->if_context;
+	struct cil_context *pkt_ctx = netif->packet_context;
+
+	/* Verify only when anonymous */
+	if (if_ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, if_ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	/* Verify only when anonymous */
+	if (pkt_ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, pkt_ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid netifcon");
+	return rc;
+}
+
+int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_genfscon *genfs = node->data;
+	struct cil_context *ctx = genfs->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid genfscon");
+	return rc;
+}
+
+int __cil_verify_filecon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_filecon *file = node->data;
+	struct cil_context *ctx = file->context;
+
+	if (ctx == NULL) {
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			cil_tree_log(node, CIL_ERR, "Invalid filecon");
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+int __cil_verify_nodecon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_nodecon *nodecon = node->data;
+	struct cil_context *ctx = nodecon->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid nodecon");
+	return rc;
+}
+
+int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_portcon *port = node->data;
+	struct cil_context *ctx = port->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid portcon");
+	return rc;
+}
+
+int __cil_verify_pirqcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_pirqcon *pirq = node->data;
+	struct cil_context *ctx = pirq->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid pirqcon");
+	return rc;
+}
+
+int __cil_verify_iomemcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_iomemcon *iomem = node->data;
+	struct cil_context *ctx = iomem->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid iomemcon");
+	return rc;
+}
+
+int __cil_verify_ioportcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_ioportcon *ioport = node->data;
+	struct cil_context *ctx = ioport->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid ioportcon");
+	return rc;
+}
+
+int __cil_verify_pcidevicecon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_pcidevicecon *pcidev = node->data;
+	struct cil_context *ctx = pcidev->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid pcidevicecon");
+	return rc;
+}
+
+int __cil_verify_devicetreecon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_devicetreecon *dt = node->data;
+	struct cil_context *ctx = dt->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid devicetreecon");
+	return rc;
+}
+
+int __cil_verify_fsuse(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_fsuse *fsuse = node->data;
+	struct cil_context *ctx = fsuse->context;
+
+	/* Verify only when anonymous */
+	if (ctx->datum.name == NULL) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid fsuse");
+	return rc;
+}
+
+int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node *node)
+{
+	int rc;
+	struct cil_list *classes = NULL;
+	struct cil_list_item *item;
+	struct cil_class *class;
+	struct cil_symtab_datum *perm_datum;
+	char *kind_str;
+
+	switch (permx->kind) {
+		case CIL_PERMX_KIND_IOCTL:
+			kind_str = CIL_KEY_IOCTL;
+			break;
+		default:
+			cil_tree_log(node, CIL_ERR, "Invalid permissionx kind (%d)", permx->kind);
+			rc = SEPOL_ERR;
+			goto exit;
+	}
+
+	classes = cil_expand_class(permx->obj);
+
+	cil_list_for_each(item, classes) {
+		class = item->data;
+		rc = cil_symtab_get_datum(&class->perms, kind_str, &perm_datum);
+		if (rc == SEPOL_ENOENT) {
+			if (class->common != NULL) {
+				rc = cil_symtab_get_datum(&class->common->perms, kind_str, &perm_datum);
+			}
+
+			if (rc == SEPOL_ENOENT) {
+				cil_tree_log(node, CIL_ERR, "Invalid permissionx: %s is not a permission of class %s", kind_str, class->datum.name);
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+		}
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	if (classes != NULL) {
+		cil_list_destroy(&classes, CIL_FALSE);
+	}
+
+	return rc;
+}
+
+int __cil_verify_avrulex(struct cil_tree_node *node)
+{
+	struct cil_avrule *avrulex = node->data;
+	return __cil_verify_permissionx(avrulex->perms.x.permx, node);
+}
+
+int __cil_verify_class(struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_class *class = node->data;
+
+	if (class->common != NULL) {
+		struct cil_class *common = class->common;
+		struct cil_tree_node *common_node = common->datum.nodes->head->data;
+		struct cil_tree_node *curr_com_perm = NULL;
+
+		for (curr_com_perm = common_node->cl_head;
+			curr_com_perm != NULL;
+			curr_com_perm = curr_com_perm->next) {
+			struct cil_perm *com_perm = curr_com_perm->data;
+			struct cil_tree_node *curr_class_perm = NULL;
+
+			for (curr_class_perm = node->cl_head;
+				curr_class_perm != NULL;
+				curr_class_perm = curr_class_perm->next) {
+				struct cil_perm *class_perm = curr_class_perm->data;
+
+				if (com_perm->datum.name == class_perm->datum.name) {
+					cil_log(CIL_ERR, "Duplicate permissions between %s common and class declarations\n", class_perm->datum.name);
+					goto exit;
+				}
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid class");
+	return rc;
+}
+
+int __cil_verify_policycap(struct cil_tree_node *node)
+{
+	int rc;
+	struct cil_policycap *polcap = node->data;
+
+	rc = sepol_polcap_getnum((const char*)polcap->datum.name);
+	if (rc == SEPOL_ERR) {
+		goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid policycap (%s)", (const char*)polcap->datum.name);
+	return rc;
+}
+
+int __cil_verify_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	int rc = SEPOL_ERR;
+	int *avrule_cnt = 0;
+	int *handleunknown;
+	int *mls;
+	int *nseuserdflt = 0;
+	int *pass = 0;
+	struct cil_args_verify *args = extra_args;
+	struct cil_complex_symtab *csymtab = NULL;
+	struct cil_db *db = NULL;
+
+	if (node == NULL || extra_args == NULL) {
+		goto exit;
+	}
+
+	db = args->db;
+	avrule_cnt = args->avrule_cnt;
+	handleunknown = args->handleunknown;
+	mls = args->mls;
+	nseuserdflt = args->nseuserdflt;
+	csymtab = args->csymtab;
+	pass = args->pass;
+
+	if (node->flavor == CIL_MACRO) {
+		*finished = CIL_TREE_SKIP_HEAD;
+		rc = SEPOL_OK;
+		goto exit;
+	} else if (node->flavor == CIL_BLOCK) {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	switch (*pass) {
+	case 0: {
+		switch (node->flavor) {
+		case CIL_USER:
+			rc = __cil_verify_user_post_eval(db, node);
+			break;
+		case CIL_SELINUXUSERDEFAULT:
+			(*nseuserdflt)++;
+			rc = SEPOL_OK;
+			break;
+		case CIL_ROLE:
+			rc = __cil_verify_role(node);
+			break;
+		case CIL_TYPE:
+			rc = __cil_verify_type(node);
+			break;
+		case CIL_AVRULE:
+			(*avrule_cnt)++;
+			rc = SEPOL_OK;
+			break;
+		case CIL_HANDLEUNKNOWN:
+			if (*handleunknown != -1) {
+				cil_log(CIL_ERR, "Policy can not have more than one handleunknown\n");
+				rc = SEPOL_ERR;
+			} else {
+				*handleunknown = ((struct cil_handleunknown*)node->data)->handle_unknown;
+				rc = SEPOL_OK;
+			}
+			break;
+		case CIL_MLS:
+			if (*mls != -1) {
+				cil_log(CIL_ERR, "Policy can not have more than one mls\n");
+				rc = SEPOL_ERR;
+			} else {
+				*mls = ((struct cil_mls*)node->data)->value;
+				rc = SEPOL_OK;
+			}
+			break;
+		case CIL_ROLETRANSITION:
+			rc = SEPOL_OK; //TODO __cil_verify_rule doesn't work quite right
+			//rc = __cil_verify_rule(node, csymtab);
+			break;
+		case CIL_TYPE_RULE:
+			rc = SEPOL_OK; //TODO __cil_verify_rule doesn't work quite right
+			//rc = __cil_verify_rule(node, csymtab);
+			break;
+		case CIL_BOOLEANIF:
+			rc = __cil_verify_booleanif(node, csymtab);
+			*finished = CIL_TREE_SKIP_HEAD;
+			break;
+		case CIL_LEVELRANGE:
+			rc = __cil_verify_named_levelrange(db, node);
+			break;
+		case CIL_CLASS:
+			rc = __cil_verify_class(node);
+			break;
+		case CIL_POLICYCAP:
+			rc = __cil_verify_policycap(node);
+			break;
+		default:
+			rc = SEPOL_OK;
+			break;
+		}
+		break;
+	}
+	case 1:	{
+		switch (node->flavor) {
+		case CIL_CONTEXT:
+			rc = __cil_verify_named_context(db, node);
+			break;
+		case CIL_NETIFCON:
+			rc = __cil_verify_netifcon(db, node);
+			break;
+		case CIL_GENFSCON:
+			rc = __cil_verify_genfscon(db, node);
+			break;
+		case CIL_FILECON:
+			rc = __cil_verify_filecon(db, node);
+			break;
+		case CIL_NODECON:
+			rc = __cil_verify_nodecon(db, node);
+			break;
+		case CIL_PORTCON:
+			rc = __cil_verify_portcon(db, node);
+			break;
+		case CIL_PIRQCON:
+			rc = __cil_verify_pirqcon(db, node);
+			break;
+		case CIL_IOMEMCON:
+			rc = __cil_verify_iomemcon(db, node);
+			break;
+		case CIL_IOPORTCON:
+			rc = __cil_verify_ioportcon(db, node);
+			break;
+		case CIL_PCIDEVICECON:
+			rc = __cil_verify_pcidevicecon(db, node);
+			break;
+		case CIL_DEVICETREECON:
+			rc = __cil_verify_devicetreecon(db, node);
+			break;
+		case CIL_FSUSE:
+			rc = __cil_verify_fsuse(db, node);
+			break;
+		case CIL_AVRULEX:
+			rc = __cil_verify_avrulex(node);
+			break;
+		case CIL_PERMISSIONX:
+			rc = __cil_verify_permissionx(node->data, node);
+			break;
+		case CIL_RANGETRANSITION:
+			rc = SEPOL_OK;
+			break;
+		default:
+			rc = SEPOL_OK;
+			break;
+		}
+		break;
+	}
+	default:
+		rc = SEPOL_ERR;
+	}
+
+exit:
+	return rc;
+}
+
+static int __cil_verify_classperms(struct cil_list *classperms, struct cil_symtab_datum *orig)
+{
+	int rc = SEPOL_ERR;
+	struct cil_list_item *curr;
+
+	cil_list_for_each(curr, classperms) {
+		if (curr->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = curr->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				return SEPOL_OK;
+			} else { /* MAP */
+				struct cil_list_item *i = NULL;
+				cil_list_for_each(i, cp->perms) {
+					struct cil_perm *cmp = i->data;
+					if (&cmp->datum == orig) {
+						rc = SEPOL_ERR;
+						goto exit;
+					}
+					rc = __cil_verify_classperms(cmp->classperms, orig);
+					if (rc != SEPOL_OK) {
+						goto exit;
+					}
+				}
+			}	
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = curr->data;
+			struct cil_classpermission *cp = cp_set->set;
+			if (&cp->datum == orig) {
+				rc = SEPOL_ERR;
+				goto exit;
+			}
+			rc = __cil_verify_classperms(cp->classperms, orig);
+			if (rc != SEPOL_OK) {
+				goto exit;
+			}
+		}
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+static int __cil_verify_classpermission(struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_classpermission *cp = node->data;
+
+	if (cp->classperms == NULL) {
+		cil_tree_log(node, CIL_ERR, "Classpermission %s does not have a classpermissionset", cp->datum.name);
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = __cil_verify_classperms(cp->classperms, &cp->datum);
+	if (rc != SEPOL_OK) {
+		cil_tree_log(node, CIL_ERR, "Found circular class permissions involving the set %s",cp->datum.name);
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
+struct cil_verify_map_args {
+	struct cil_class *class;
+	struct cil_tree_node *node;
+	int rc;
+};
+
+static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+	int rc = SEPOL_ERR;
+	struct cil_verify_map_args *map_args = args;
+	struct cil_perm *cmp = (struct cil_perm *)d;
+
+	if (cmp->classperms == NULL) {
+		cil_tree_log(map_args->node, CIL_ERR, "Map class %s does not have a classmapping for %s", map_args->class->datum.name, cmp->datum.name);
+		map_args->rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = __cil_verify_classperms(cmp->classperms, &cmp->datum);
+	if (rc != SEPOL_OK) {
+		cil_tree_log(map_args->node, CIL_ERR, "Found circular class permissions involving the map class %s and permission %s", map_args->class->datum.name, cmp->datum.name);
+		map_args->rc = SEPOL_ERR;
+		goto exit;
+	}
+
+exit:
+	return SEPOL_OK;
+}
+
+static int __cil_verify_map_class(struct cil_tree_node *node)
+{
+	struct cil_class *mc = node->data;
+	struct cil_verify_map_args map_args;
+
+	map_args.class = mc;
+	map_args.node = node;
+	map_args.rc = SEPOL_OK;
+
+	cil_symtab_map(&mc->perms, __verify_map_perm_classperms, &map_args);
+
+	if (map_args.rc != SEPOL_OK) {
+		return SEPOL_ERR;
+	}
+
+	return SEPOL_OK;
+}
+
+int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+	int rc = SEPOL_ERR;
+
+	if (node->flavor == CIL_MACRO) {
+		*finished = CIL_TREE_SKIP_HEAD;
+		rc = SEPOL_OK;
+		goto exit;
+	} else if (node->flavor == CIL_BLOCK) {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		rc = SEPOL_OK;
+		goto exit;
+	}
+
+	switch (node->flavor) {
+	case CIL_USER:
+		rc = __cil_verify_user_pre_eval(node);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+		break;
+	case CIL_MAP_CLASS:
+		rc = __cil_verify_map_class(node);
+		break;
+	case CIL_CLASSPERMISSION:
+		rc = __cil_verify_classpermission(node);
+		break;
+	default:
+		rc = SEPOL_OK;
+		break;
+	}
+
+exit:
+	return rc;
+}
diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h
new file mode 100644
index 0000000..bda1565
--- /dev/null
+++ b/libsepol/cil/src/cil_verify.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_VERIFY_H_
+#define CIL_VERIFY_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+enum cil_syntax {
+	CIL_SYN_STRING      = 1 << 0,
+	CIL_SYN_LIST        = 1 << 1,
+	CIL_SYN_EMPTY_LIST  = 1 << 2,
+	CIL_SYN_N_LISTS     = 1 << 3,
+	CIL_SYN_N_STRINGS   = 1 << 4,
+	CIL_SYN_END         = 1 << 5
+};
+
+struct cil_args_verify {
+	struct cil_db *db;
+	struct cil_complex_symtab *csymtab;
+	int *avrule_cnt;
+	int *handleunknown;
+	int *mls;
+	int *nseuserdflt;
+	int *pass;
+};
+
+int __cil_verify_name(const char *name);
+int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len);
+int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor);
+int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor);
+int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op);
+int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list);
+int __cil_verify_ranges(struct cil_list *list);
+int __cil_verify_ordered_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args);
+int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor);
+int __cil_verify_initsids(struct cil_list *sids);
+int __cil_verify_senscat(struct cil_sens *sens, struct cil_cat *cat);
+int __cil_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
+int __cil_pre_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
+
+#endif
diff --git a/libsepol/cil/src/dso.h b/libsepol/cil/src/dso.h
new file mode 100644
index 0000000..a06e349
--- /dev/null
+++ b/libsepol/cil/src/dso.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H	1
+
+#if !defined(SHARED) || defined(ANDROID)
+    #define DISABLE_SYMVER 1
+#endif
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal)	\
+     extern __typeof (fct) internal;	\
+     extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/libsepol/cil/test/integration_testing/mls_policy.cil b/libsepol/cil/test/integration_testing/mls_policy.cil
new file mode 100644
index 0000000..535ac11
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/mls_policy.cil
@@ -0,0 +1,115 @@
+(class testing (read open close write exec))
+(class fooclass (read open close write exec))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(categoryalias c0 cat)
+(categoryorder (c0 c1 c2 c3 c4))
+(categoryset catset (c0 c2 c3))
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivityalias s3 sens)
+(dominance (s0 s1 s2 s3))
+(sensitivitycategory s0 (c0 c2 c3))
+(sensitivitycategory s0 (cat))
+; the following causes a segfault
+;(sensitivitycategory sens (c2))
+(type foo_t)
+(type typea_t)
+(type typeb_t)
+(type typec_t)
+(role foo_r)
+(role rolea_r)
+(role roleb_r)
+(user foo_u)
+(user user_u)
+(userrole foo_u foo_r)
+(level low (s0 catset))
+(level high (s0 (c0)))
+(level test_l (s0 (cat)))
+
+(sid test_sid)
+(sidcontext test_sid (foo_u foo_r foo_t (s0 (c0)) (s0 (c0))))
+(sid test_sid_anon_l)
+(sidcontext test_sid_anon_l (foo_u foo_r foo_t low high))
+
+(context con (foo_u foo_r foo_t low high))
+(context con_anon_l (foo_u foo_r foo_t (s0 (c0)) high))
+(fsuse xattr ext3 con)
+(fsuse xattr ext3 con_anon_l)
+
+(netifcon eth0 con con_anon_l)
+
+(ipaddr ip_v4 192.25.35.200)
+(ipaddr netmask 192.168.1.1)
+(ipaddr ip_v6 2001:0DB8:AC10:FE01::)
+(ipaddr netmask_v6 2001:0DE0:DA88:2222::)
+; will need anon levels
+(nodecon ip_v4 netmask con)
+(nodecon ip_v6 netmask_v6 con_anon_l)
+
+;needs anon levels
+(portcon type 25 con)
+
+(filecon root path file con)
+
+(genfscon type path con)
+
+(netifcon eth0 con con_anon_l)
+
+(typemember typea_t typeb_t testing typec_t)
+(typechange typea_t typeb_t testing typec_t)
+(typetransition typea_t typeb_t testing typec_t)
+
+(permissionset permset (open close))
+(allow typea_t typeb_t testing (write))
+(allow typea_t typeb_t testing permset)
+
+(roleallow rolea_r roleb_r)
+
+(rolebounds rolea_r roleb_r)
+
+(roletransition foo_r foo_t testing rolea_r)
+
+(level l2 (s0 (c0)))
+(level h2 (s0 (c0)))
+(mlsconstrain (fooclass testing)(open close)(eq l2 h2))
+
+(common fooclass (open))
+(classcommon fooclass fooclass)
+
+(rangetransition typea_t typeb_t fooclass low high)
+
+(nametypetransition string typea_t typeb_t fooclass foo_t)
+
+(typepermissive foo_t)
+
+(typebounds typea_t typeb_t)
+
+(block test_b
+ 	(typealias .test_b.test typea_t)
+	(type test))
+
+(attribute attrs)
+(attributetypes attrs (foo_t))
+
+(roletype foo_r foo_t)
+
+(userbounds user_u foo_u)
+
+(userrole user_u foo_r)
+
+(bool foo_b true)
+(bool baz_b false)
+(booleanif (&& foo_b baz_b)
+ 	(allow typea_t typeb_t fooclass(read)))
+;(class baz (read))
+;(booleanif (&& foo_b baz_b)
+;	(allow foo_b baz_b fooclass (read)))
+
+
diff --git a/libsepol/cil/test/integration_testing/nonmls.cil b/libsepol/cil/test/integration_testing/nonmls.cil
new file mode 100644
index 0000000..382b95d
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/nonmls.cil
@@ -0,0 +1,86 @@
+(class testing (read open close write exec))
+(class fooclass (read open close write exec))
+
+(type foo_t)
+(type typea_t)
+(type typeb_t)
+(type typec_t)
+(role foo_r)
+(role rolea_r)
+(role roleb_r)
+(user foo_u)
+(user user_u)
+(userrole foo_u foo_r)
+
+(sid test_sid)
+;(sidcontext test_sid (foo_u foo_r foo_t (s0 (c0)) (s0 (c0))))
+;(sid test_sid_anon_l)
+
+;(fsuse xattr ext3 con)
+;(fsuse xattr ext3 con_anon_l)
+
+;(netifcon eth0 con con_anon_l)
+
+(ipaddr ip_v4 192.25.35.200)
+(ipaddr netmask 192.168.1.1)
+(ipaddr ip_v6 2001:0DB8:AC10:FE01::)
+(ipaddr netmask_v6 2001:0DE0:DA88:2222::)
+; will need anon levels
+;(nodecon ip_v4 netmask con)
+;(nodecon ip_v6 netmask_v6 con_anon_l)
+
+;needs anon levels
+;(portcon type 25 con)
+
+;(filecon root path file con)
+
+;(genfscon type path con)
+
+;(netifcon eth0 con con_anon_l)
+
+(typemember typea_t typeb_t testing typec_t)
+(typechange typea_t typeb_t testing typec_t)
+(typetransition typea_t typeb_t testing typec_t)
+
+(permissionset permset (open close))
+(allow typea_t typeb_t testing (write))
+(allow typea_t typeb_t testing permset)
+
+(roleallow rolea_r roleb_r)
+
+(rolebounds rolea_r roleb_r)
+
+(roletransition foo_r foo_t testing rolea_r)
+
+(common fooclass (open))
+(classcommon fooclass fooclass)
+
+
+(nametypetransition string typea_t typeb_t fooclass foo_t)
+
+(typepermissive foo_t)
+
+(typebounds typea_t typeb_t)
+
+(block test_b
+ 	(typealias .test_b.test typea_t)
+	(type test))
+
+(attribute attrs)
+(attributetypes attrs (foo_t))
+
+(roletype foo_r foo_t)
+
+(userbounds user_u foo_u)
+
+(userrole user_u foo_r)
+
+;(bool foo_b true)
+;(bool baz_b false)
+;(booleanif (&& foo_b baz_b)
+; 	(allow typea_t typeb_t fooclass(read)))
+;(class baz (read))
+;(booleanif (&& foo_b baz_b)
+;	(allow foo_b baz_b fooclass (read)))
+
+
diff --git a/libsepol/cil/test/integration_testing/nonmls.conf b/libsepol/cil/test/integration_testing/nonmls.conf
new file mode 100644
index 0000000..729c7b1
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/nonmls.conf
@@ -0,0 +1,76 @@
+
+class testing
+class fooclass
+
+sid test_sid
+#end
+
+#sid decl
+sid security
+
+
+class testing
+{
+	read
+	open
+	close
+	write
+	exec
+}
+class fooclass
+{
+	read
+	open
+	close
+	write
+	exec
+}
+#end
+
+#attribs
+
+attribute attrs;
+#end
+
+
+type foo_t, attrs;
+type typea_t;
+type typeb_t;
+type typec_t;
+#end
+
+
+bool foo_b true;
+bool baz_b false;
+#end
+
+
+role foo_r types foo_t;
+role rolea_r;
+role roleb_r;
+#end
+
+#role decl
+
+
+allow typea_t typeb_t : testing write;
+allow typea_t typeb_t : testing {open close};
+type_transition typea_t typeb_t : testing typec_t;
+#end
+
+#audit rules
+#dontaudit {kernel} unknown : dir search;
+
+
+allow rolea_r roleb_r;
+#end
+
+#rbac stuff
+#allow system {guest local_user};
+#allow local_user guest;
+
+
+user foo_u roles foo_r;
+#end
+
+sid test_sid foo_u:foo_r:foo_t 
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil
new file mode 100644
index 0000000..321fe2f
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil
@@ -0,0 +1,42 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil
new file mode 100644
index 0000000..9e84191
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil
new file mode 100644
index 0000000..36aa687
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_easy.cil b/libsepol/cil/test/integration_testing/ordered_lists_easy.cil
new file mode 100644
index 0000000..36df1e6
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_easy.cil
@@ -0,0 +1,38 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s0 s1 s2 s3 s4 s5 s6 s7 s8 s9))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c2 c3 c4 c5))
+(categoryorder (c0 c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c7 c8 c9))
+
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_hard.cil b/libsepol/cil/test/integration_testing/ordered_lists_hard.cil
new file mode 100644
index 0000000..f00c5b1
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_hard.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/small.cil b/libsepol/cil/test/integration_testing/small.cil
new file mode 100644
index 0000000..9973166
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/small.cil
@@ -0,0 +1,5 @@
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
diff --git a/libsepol/cil/test/unit/AllTests.c b/libsepol/cil/test/unit/AllTests.c
new file mode 100644
index 0000000..40080c8
--- /dev/null
+++ b/libsepol/cil/test/unit/AllTests.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdio.h>
+#include "CuTest.h"
+#include "../../src/cil_log.h"
+
+CuSuite* CilTreeGetSuite(void);
+CuSuite* CilTreeGetResolveSuite(void);
+CuSuite* CilTreeGetBuildSuite(void);
+CuSuite* CilTestFullCil(void);
+
+void RunAllTests(void) {
+    /* disable cil log output */
+    cil_set_log_level(0);
+
+    CuString *output  = CuStringNew();
+    CuSuite* suite = CuSuiteNew();
+    CuSuite* suiteResolve = CuSuiteNew();
+    CuSuite* suiteBuild = CuSuiteNew(); 
+    CuSuite* suiteIntegration = CuSuiteNew();
+
+    CuSuiteAddSuite(suite, CilTreeGetSuite());
+    CuSuiteAddSuite(suiteResolve, CilTreeGetResolveSuite());
+    CuSuiteAddSuite(suiteBuild, CilTreeGetBuildSuite());
+    CuSuiteAddSuite(suiteIntegration, CilTestFullCil());
+
+    CuSuiteRun(suite);
+    CuSuiteDetails(suite, output);
+    CuSuiteSummary(suite, output);
+
+    CuSuiteRun(suiteResolve);
+    CuSuiteDetails(suiteResolve, output);
+    CuSuiteSummary(suiteResolve, output);
+
+    CuSuiteRun(suiteBuild);
+    CuSuiteDetails(suiteBuild, output);
+    CuSuiteSummary(suiteBuild, output);
+
+    CuSuiteRun(suiteIntegration);
+    CuSuiteDetails(suiteIntegration, output);
+    CuSuiteSummary(suiteIntegration, output);
+    printf("\n%s\n", output->buffer);
+}
+
+int main(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[]) {
+    RunAllTests();
+
+    return 0;
+}
diff --git a/libsepol/cil/test/unit/CilTest.c b/libsepol/cil/test/unit/CilTest.c
new file mode 100644
index 0000000..c0c2f3b
--- /dev/null
+++ b/libsepol/cil/test/unit/CilTest.c
@@ -0,0 +1,1974 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+
+#include "test_cil.h"
+#include "test_cil_tree.h"
+#include "test_cil_list.h"
+#include "test_cil_symtab.h"
+#include "test_cil_parser.h"
+#include "test_cil_lexer.h"
+#include "test_cil_build_ast.h"
+#include "test_cil_resolve_ast.h"
+#include "test_cil_fqn.h"
+#include "test_cil_copy_ast.h"
+#include "test_cil_post.h"
+#include "test_integration.h"
+
+void set_cil_file_data(struct cil_file_data **data) {
+	struct cil_file_data *new_data = malloc(sizeof(*new_data));
+	FILE *file;
+	struct stat filedata;
+	uint32_t file_size;
+	char *buffer;
+
+	file = fopen("test/policy.cil", "r");
+	if (!file) {
+	    fprintf(stderr, "Could not open file\n");
+	    exit(1);
+	}
+	if (stat("test/policy.cil", &filedata) == -1) {
+	    printf("Could not stat file\n");
+	    exit(1);
+	}
+	file_size = filedata.st_size;
+
+	buffer = malloc(file_size + 2);
+	if(fread(buffer, file_size, 1, file) < 1) {
+		exit(1);
+	}
+	memset(buffer+file_size, 0, 2);
+	fclose(file);
+
+
+	new_data->buffer = buffer;
+	new_data->file_size = file_size;
+
+	*data = new_data;
+
+}
+
+void gen_test_tree(struct cil_tree **test_root, char *line[]) {
+	struct cil_tree *new_tree = malloc(sizeof(*new_tree));
+	struct cil_tree_node *node, *item, *current;
+
+	cil_tree_init(&new_tree);
+	new_tree->root->flavor = CIL_ROOT;
+	current = new_tree->root;
+	
+	char **i = line;
+	do {
+	    if (*i[0] == '(') {
+	        cil_tree_node_init(&node);
+	        node->parent = current;
+	        node->flavor = CIL_PARSE_NODE;
+	        node->line = 0;
+	        if (current->cl_head == NULL)
+	            current->cl_head = node;
+	        else
+	            current->cl_tail->next = node;
+	        current->cl_tail = node;
+	        current = node;
+	    }
+	    else if (*i[0] == ')')
+	        current = current->parent;
+	    else {
+	        cil_tree_node_init(&item);
+	        item->parent = current;
+	        item->data = cil_strdup(*i);
+	        item->flavor = CIL_PARSE_NODE;
+	        item->line = 0;
+	        if (current->cl_head == NULL) {
+	            current->cl_head = item;
+	        }
+	        else {
+	            current->cl_tail->next = item;
+	        }
+	        current->cl_tail = item;
+	    }
+	    i++;
+	} while(*i != NULL);
+
+	*test_root = new_tree;
+}
+
+void test_symtab_init(CuTest *tc) {
+	struct cil_db *test_new_db;
+	test_new_db = malloc(sizeof(*test_new_db));
+
+	uint32_t rc = 0, i =0;
+	
+	for (i = 0; i < CIL_SYM_NUM; i++) {
+	    rc = symtab_init(&test_new_db->symtab[i], cil_sym_sizes[CIL_SYM_ARRAY_ROOT][i]);
+	    CuAssertIntEquals(tc, 0, rc);
+	    // TODO CDS add checks to make sure the symtab looks correct
+	}
+
+	free(test_new_db);
+}
+
+void test_symtab_init_no_table_neg(CuTest *tc) {
+	struct cil_db *test_new_db;
+	test_new_db = malloc(sizeof(*test_new_db));
+
+	int rc = symtab_init(&test_new_db->symtab[0], (uint32_t)SIZE_MAX);
+	CuAssertIntEquals(tc, -1, rc);
+
+	free(test_new_db);
+}
+
+CuSuite* CilTreeGetResolveSuite(void) {
+	CuSuite* suite = CuSuiteNew();
+	
+	/* test_cil_resolve_ast.c */
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_curr_null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes_inval_perm_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_name);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_invalid_type_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_type_in_multiple_attrs);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_multiple_excludes_with_not);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_multiple_types_with_and);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_using_attr);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_name_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_undef_type_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_not);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_undef_type_not_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typeattributeset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_typealias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typealias_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typealias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typealias_notype_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_typebounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_repeatbind_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_type1_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_type2_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typebounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typebounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_typepermissive);
+	SUITE_ADD_TEST(suite, test_cil_resolve_typepermissive_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typepermissive);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typepermissive_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_src_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_tgt_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_class_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_dest_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nametypetransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nametypetransition_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_type1_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_type2_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_class_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_l_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_l_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_h_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_h_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_level_l_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_level_h_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_l);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_l_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_h);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_h_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rangetransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rangetransition_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_classcommon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classcommon_no_class_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classcommon_no_common_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_classcommon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_classcommon_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_named);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_inmacro);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_inmacro_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_named_classmapname_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_classmapname_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_permset_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_exists_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_role1_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_role2_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rolebounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rolebounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_sensalias_sensdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sensalias_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_catalias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catalias_catdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catalias);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catalias_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_catorder);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catorder_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catorder);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catorder_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_dominance);
+	SUITE_ADD_TEST(suite, test_cil_resolve_dominance_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_dominance);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_dominance_neg);
+	//TODO: test for __cil_set_order
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_catset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catset_catlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catset_catlist_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_catrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catrange_catloworder_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cathighorder_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cat1_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cat2_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catrange_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catsetname);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catsetname_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_sublist);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_missingsens_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_category_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_senscat_currrangecat);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_senscat);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_senscat_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_level);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_catlist);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_catset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_catset_name_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_sens_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_cat_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_level_senscat_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_level);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_level_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl);
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl_low_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl_high_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl);
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl_low_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl_high_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_levelrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_levelrange_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_constrain);
+	SUITE_ADD_TEST(suite, test_cil_resolve_constrain_class_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_constrain_perm_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_constrain_perm_resolve_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_constrain);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_constrain_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_mlsconstrain);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_mlsconstrain_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_macro);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_macro_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_namedrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_namedrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_user_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_role_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_type_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_context_anon_level_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_context_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_resultdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_roleallow);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roleallow_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roleallow_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roleallow);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roleallow_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_namedpermlist);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_permlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_unnamedcps_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon_namedpermlist);
+	SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon_permlist_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset_permdne_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_firsttype_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_secondtype_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_class_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_avrule_perm_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_src_nores_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_class_nores_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_datum_null_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_objdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_resultdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_transition);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_transition_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_objdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_resultdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_change);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_change_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_srcdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_tgtdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_objdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_resultdecl_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_member);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_member_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_filecon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_filecon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_filecon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_filecon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_filecon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_filecon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_portcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_portcon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_portcon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_portcon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_portcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_portcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_genfscon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_genfscon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_genfscon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipv4);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipv6);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonipaddr_ipv4);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonnetmask_ipv4);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonipaddr_ipv6);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonnetmask_ipv6);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_diffipfam_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipaddr_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_netmask_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon_netmask_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_otf_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_interface_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed);
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed_packet_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed_otf_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_netifcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_netifcon_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pirqcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pirqcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_iomemcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_iomemcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_ioportcon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_ioportcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_anon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pcidevicecon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pcidevicecon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_fsuse);
+	SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_fsuse);
+	//SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_fsuse_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext);
+	SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_levels);
+	SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context);
+	SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context_wrongname_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context_invaliduser_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sidcontext); 
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sidcontext_neg); 
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_blockinherit);
+	SUITE_ADD_TEST(suite, test_cil_resolve_blockinherit_blockstrdne_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_blockinherit);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_in_block);
+	SUITE_ADD_TEST(suite, test_cil_resolve_in_blockstrdne_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_in_macro);
+	SUITE_ADD_TEST(suite, test_cil_resolve_in_optional);
+	
+	//SUITE_ADD_TEST(suite, test_cil_resolve_call1_noparam);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_type);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_role);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_user);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_sens);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_cat);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_class);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_classmap);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_permset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_permset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_named);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_level);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_level_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_level_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr_anon_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknown_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknowncall_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_extraargs_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_copy_dup);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_missing_arg_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_paramsflavor_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknownflavor_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call1);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call1_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_type);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_role);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_user);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_sens);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_cat);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_catset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_catset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_permset);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_permset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_classpermset_named);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_classpermset_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_class);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_classmap);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_level);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_level_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_ipaddr_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_call2_unknown_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call2);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call2_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_multipleparams);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_diffflavor);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_callnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_namenull_neg);
+	//SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_callargsnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_name_neg);
+	
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_bools);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_tunables);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_type);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_role);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_user);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_neg);
+//	SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_emptystr_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_boolif);
+	SUITE_ADD_TEST(suite, test_cil_resolve_boolif_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_boolif);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_boolif_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_and);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_not);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_or);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_xor);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_eq);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_neq);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_oper1);
+	SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_oper2);
+	//SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_tunif_false);
+	SUITE_ADD_TEST(suite, test_cil_resolve_tunif_true);
+	SUITE_ADD_TEST(suite, test_cil_resolve_tunif_resolveexpr_neg);
+	//SUITE_ADD_TEST(suite, test_cil_resolve_tunif_evaluateexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_tunif);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_tunif_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userbounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_exists_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_user1_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_user2_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userbounds);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userbounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletype);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletype_type_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_roletype_role_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype_role_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype_type_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrole);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrole_user_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrole_role_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole_user_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole_role_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_macro);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_macro_neg);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_anon);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_anon_neg);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_user_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userlevel);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userlevel_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_macro);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_macro_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_anon);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_anon_neg);	
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_user_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrange);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrange_neg); 
+	
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_optional_enabled);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_optional_disabled);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_block);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_user);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_role);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_type);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_typealias);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_common);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_class);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_bool);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sens);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_cat);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_catset);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sid);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_macro);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_context);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_level);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_policycap);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_perm);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_catalias);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_tunable);
+	SUITE_ADD_TEST(suite, test_cil_disable_children_helper_unknown);
+	
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_callstack);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optional);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_macro);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack_tunable_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack_macro_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_extraargsnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optfailedtoresolve);
+
+	return suite;
+}
+
+CuSuite* CilTreeGetBuildSuite(void) {
+	CuSuite* suite = CuSuiteNew();
+
+	/* test_cil_build_ast.c */
+	SUITE_ADD_TEST(suite, test_cil_build_ast);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_treenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_suberr_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_parse_to_list);
+	SUITE_ADD_TEST(suite, test_cil_parse_to_list_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_parse_to_list_listnull_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_set_to_list);
+	SUITE_ADD_TEST(suite, test_cil_set_to_list_listnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_set_to_list_tree_node_null_neg);
+	SUITE_ADD_TEST(suite, test_cil_set_to_list_cl_head_null_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_block);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_justblock_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_treenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_nodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_block_nodeparentnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_block);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_block_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_namelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_namenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_blockinherit);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_blockinherit_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_perm);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_nodenull_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_permset);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_noperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_emptyperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_permset_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_permset);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_permset_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes);
+	SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes_failgen_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_fill_permset);
+	SUITE_ADD_TEST(suite, test_cil_fill_permset_sublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_permset_startpermnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_permset_permsetnull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_in);
+	SUITE_ADD_TEST(suite, test_cil_gen_in_blockstrnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_in_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_in_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_in_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_in_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_in);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_in_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_class);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_nodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_noclassname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_namesublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_noperms);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_permsnotinlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_extrapermlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_class_listinlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_class);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_class_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_anonperms);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_anonperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_namedperms);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_emptypermslist_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_noperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_classnodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_classpermset_cpsnull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_emptyperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classpermset_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classpermset);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classpermset_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_dupeperm_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_astnull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_emptyperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmap_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmap);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmap_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_anonpermset);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_anonpermset_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_namedpermset);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_noclassmapname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_noclassmapperm_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_nopermissionsets_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classmapping_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmapping);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmapping_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_common);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_twoperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_permsublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_common_noperms_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_common);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_common_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_sid);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sid_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sid);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sid_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_namedcontext);
+//	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_halfcontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_empty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_dblname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_pcurrnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_astnodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sidcontext);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sidcontext_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_type);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattribute);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattribute);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattribute_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_notype1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_type1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_notype2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_type2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typebounds_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typebounds);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typebounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_typeinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typepermissive);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typepermissive_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nostr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_strinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nosrc_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_srcinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_notgt_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_tgtinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_classinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nodest_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_destinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_nametypetransition);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_nametypetransition_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_namedtransition);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_low_l);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_low_l_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_high_l);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_high_l_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nofirsttype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_firsttype_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nosecondtype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_secondtype_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_class_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nolevel_l_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nolevel_h_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rangetransition);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rangetransition_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_and);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_or);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_xor);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not_noexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_eq);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_neq);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_emptyargs_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_missingoperator_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_arg1null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_arg2null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_extraarg_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_stacknull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_unknowncond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_unknowncond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_nested);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_nested_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_extra_parens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_nocond);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_nocond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_notruelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_boolif_empty_cond_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_boolif);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_boolif_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_unknowncond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_unknowncond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_nocond);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_nested);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_nested_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_extra_parens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_nocond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_tunif_notruelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_tunif);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_tunif_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_nocond_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_condblock_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_true);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_true_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_false);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_false_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_incomplete_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_incomplete_neg2);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_extratype_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typealias);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typealias_notype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typealias_astnull_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_and_two_types);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_not);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_exclude_attr);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_exclude_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_emptylists_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_listinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattributeset);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattributeset_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_notype1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_type1_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_notype2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_type2_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userbounds_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userbounds);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userbounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_role);
+	SUITE_ADD_TEST(suite, test_cil_gen_role_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_role_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_role_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_role_extrarole_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_role_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_role);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_role_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_srcnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_tgtnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_resultnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletransition_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletransition);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletransition_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_tunable_true);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_tunable_false);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_none_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_notbool_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_boolname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_extraname_false_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_bool_extraname_true_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_tunable);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_tunable_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1type);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1t1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t2type);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t2t2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1role);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1r1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r2role);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r2r2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1t2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_r1r2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1r2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1u2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1user);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1u1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u2user);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u2u2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l2h2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1h1);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1h2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1l2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1h2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_noexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_emptyparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_extraparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_noexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_noexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_stacknull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_operatorinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incorrectcall_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_roleallow);
+	SUITE_ADD_TEST(suite, test_cil_gen_roleallow_dbnull_neg);
+        SUITE_ADD_TEST(suite, test_cil_gen_roleallow_currnull_neg);
+        SUITE_ADD_TEST(suite, test_cil_gen_roleallow_astnull_neg);
+        SUITE_ADD_TEST(suite, test_cil_gen_roleallow_srcnull_neg);
+        SUITE_ADD_TEST(suite, test_cil_gen_roleallow_tgtnull_neg);
+        SUITE_ADD_TEST(suite, test_cil_gen_roleallow_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roleallow);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roleallow_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_norole1_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_role1_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_norole2_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_role2_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rolebounds);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rolebounds_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_permset);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_permset_anon);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourceparens);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourceemptyparen_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetparens);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetemptyparen_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourcedomainnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetdomainnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_objectclassnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_permsnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_avrule_twolists_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_allow);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_allow_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_auditallow);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_auditallow_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_dontaudit);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_dontaudit_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_neverallow);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_neverallow_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_srcnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_tgtnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_objnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_resultnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_transition);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_transition_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_srcnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_tgtnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_objnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_resultnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_change);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_change_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_srcnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_tgtnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_objnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_resultnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_member);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_member_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_user);
+	SUITE_ADD_TEST(suite, test_cil_gen_user_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_user_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_user_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_user_nouser_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_user_xsinfo_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_user);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_user_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_anon_level);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_anon_level_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_usernull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_userrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_levelnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_levelrangeempty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userlevel_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userlevel);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userlevel_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_named);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_anon);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_usernull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonuser_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_rangenamenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonrangeinvalid_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonrangeempty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrange_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrange);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrange_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_sensnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_senslist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensitivity);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensitivity_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_sensnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_senslist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_aliasnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_aliaslist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_sensalias_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensalias_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_category);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_catnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_catlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_category_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_category);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_category_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_catset);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_namenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_setnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_namelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_nodefail_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_notset_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catset_settolistfail_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catset);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catset_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_catnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_aliasnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catalias_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catalias);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catalias_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_norange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_emptyrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_extrarange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catrange_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catrange);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catrange_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_empty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_rolelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_roletype_sublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_roletype_typelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletype);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletype_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_empty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_userlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_userrole_sublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_userrole_rolelist_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrole);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrole_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_missingclassname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_noperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_classcommon_extraperms_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_classcommon);	
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_classcommon_neg);	
+
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_missingcats_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_nosublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_catorder_nestedcat_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catorder);	
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catorder_neg);	
+
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance);
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance_nosensitivities_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_dominance_nosublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_dominance);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_dominance_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_nosublist);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_nosensitivities_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_sublist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_senscat_nocat_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_senscat);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_senscat_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_fill_level);
+	SUITE_ADD_TEST(suite, test_cil_fill_level_sensnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_level_levelnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_level_nocat);
+	SUITE_ADD_TEST(suite, test_cil_fill_level_emptycat_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_level);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_emptysensparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_emptycat_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_nosens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_level_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_level);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_level_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangeinvalid_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_namenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangeempty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_levelrange_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_levelrange);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_levelrange_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_noperm_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_noclass_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_noperm_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_expression_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_constrain_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_constrain);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_constrain_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_mlsconstrain);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_mlsconstrain_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_fill_context);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_nouser_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_norole_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_notype_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_nolowlvl_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_nohighlvl_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl_nocontextlow_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl_nocontexthigh_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_context);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_notinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_extralevel_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_emptycontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_doubleparen_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_norole_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_roleinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_notype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_typeinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_nolevels_neg);
+//	SUITE_ADD_TEST(suite, test_cil_gen_context_nosecondlevel_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_nouser_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_context_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_context);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_context_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_file);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_dir);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_char);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_block);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_socket);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_pipe);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_symlink);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_any);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_str1null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_str1_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_str2null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_str2_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_classnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_class_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_contextnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_filecon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_filecon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_filecon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_udp);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_tcp);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_unknownprotocol_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange_one_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange_morethanone_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_singleport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_lowport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_highport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_str1null_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_str1parens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_portnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_contextnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_portcon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_portcon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_portcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_fill_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrnodenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_extra_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipanon);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipanon_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmasknull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmaskanon);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmaskanon_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_contextnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_nodecon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_nodecon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_nodecon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_anon_context);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_typenull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_typeparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_pathnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_pathparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_contextnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_context_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_genfscon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_genfscon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_genfscon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_emptysecondlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_extra_nested_secondlist_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_missingobjects_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_secondnested_missingobjects_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_ethmissing_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_interfacemissing_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_netifcon_packetmissing_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_netifcon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_netifcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_pirqnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_nopirq_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_pirqrange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_anoncontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pirqcon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pirqcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_firstnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_secondnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_empty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_singleiomem_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_noiomem_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_anoncontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_iomemcon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_iomemcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_firstnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_secondnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_empty_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_singleioport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportnotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_noioport_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_anoncontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ioportcon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ioportcon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_pcidevicenotint_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_nopcidevice_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_pcidevicerange_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_anoncontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pcidevicecon);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pcidevicecon_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_anoncontext);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_anoncontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_xattr);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_task);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_transition);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_invalidtype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_notype_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_typeinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_nofilesystem_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_filesysteminparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_nocontext_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_emptyconparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_fsuse_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_fsuse);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_fsuse_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_noparams);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_type);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_role);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_user);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_sensitivity);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_category);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_catset);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_level);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_class);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_classmap);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_permset);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_duplicate);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_duplicate_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_unknown_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_unnamed_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_noparam_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_nosecondparam_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_noparam_name_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_emptyparam_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_macro_paramcontainsperiod_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_nested_macro_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_call);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_noargs);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_anon);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_empty_call_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_name_inparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_call_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_call);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_call_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_optional);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_emptyoptional);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_unnamed_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_optional_norule_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_optional);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_optional_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_policycap_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_policycap);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_policycap_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv4);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv4_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv6);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv6_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_noname_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_nameinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_noip_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipinparens_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_extra_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_dbnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_currnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_astnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ipaddr_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_extraargsnull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_build_ast_last_child_helper);
+	SUITE_ADD_TEST(suite, test_cil_build_ast_last_child_helper_extraargsnull_neg);
+	
+	return suite;
+}
+
+CuSuite* CilTreeGetSuite(void) {
+	CuSuite* suite = CuSuiteNew();
+
+	/* CilTest.c */
+	SUITE_ADD_TEST(suite, test_symtab_init);
+	SUITE_ADD_TEST(suite, test_symtab_init_no_table_neg);
+
+
+	/* test_cil.c */
+	SUITE_ADD_TEST(suite, test_cil_symtab_array_init);
+
+	SUITE_ADD_TEST(suite, test_cil_db_init);
+
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_block);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_class);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_root);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_flavor_neg);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_null_neg);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_node_null_neg);
+	SUITE_ADD_TEST(suite, test_cil_get_symtab_parent_null_neg);
+
+
+	/* test_cil_list.c */
+	SUITE_ADD_TEST(suite, test_cil_list_append_item);
+	SUITE_ADD_TEST(suite, test_cil_list_append_item_append);
+	SUITE_ADD_TEST(suite, test_cil_list_append_item_append_extra);
+	SUITE_ADD_TEST(suite, test_cil_list_append_item_listnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_list_append_item_itemnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_list_prepend_item_prepend);
+	SUITE_ADD_TEST(suite, test_cil_list_prepend_item_prepend_neg);
+	SUITE_ADD_TEST(suite, test_cil_list_prepend_item_listnull_neg);
+	SUITE_ADD_TEST(suite, test_cil_list_prepend_item_itemnull_neg);
+
+
+	/* test_cil_symtab.c */
+	SUITE_ADD_TEST(suite, test_cil_symtab_insert);
+
+
+	/* test_cil_tree.c */
+	SUITE_ADD_TEST(suite, test_cil_tree_init);
+	SUITE_ADD_TEST(suite, test_cil_tree_node_init);
+
+
+	/* test_cil_lexer.c */
+	SUITE_ADD_TEST(suite, test_cil_lexer_setup);
+	SUITE_ADD_TEST(suite, test_cil_lexer_next);
+
+
+	/* test_cil_parser.c */
+	SUITE_ADD_TEST(suite, test_cil_parser);
+
+
+	/* test_cil_fqn.c */
+	SUITE_ADD_TEST(suite, test_cil_qualify_name);
+	SUITE_ADD_TEST(suite, test_cil_qualify_name_cil_flavor);
+
+	/* test cil_copy_ast.c */
+	SUITE_ADD_TEST(suite, test_cil_copy_list);
+	SUITE_ADD_TEST(suite, test_cil_copy_list_sublist);
+	SUITE_ADD_TEST(suite, test_cil_copy_list_sublist_extra);
+	SUITE_ADD_TEST(suite, test_cil_copy_list_orignull_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_block);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_block);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_block_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_perm);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_perm);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_perm_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_class);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_class);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_class_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_common);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_common);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_common_dup_neg);
+
+	SUITE_ADD_TEST(suite, test_cil_copy_classcommon);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_classcommon);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_sid);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sid);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sid_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_sidcontext);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sidcontext);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_user);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_user);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_user_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_role);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_role);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_role_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_userrole);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_userrole);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_type);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_typeattribute);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typeattribute);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typeattribute_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_typealias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typealias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typealias_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_bool);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_bool);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_bool_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_avrule);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_avrule);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_type_rule);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type_rule);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_sens);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sens);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sens_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sensalias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sensalias_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_cat);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_cat);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_cat_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_catalias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catalias);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catalias_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_senscat);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_senscat);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_catorder);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catorder);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_dominance);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_dominance);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_level);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_level);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_level_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_fill_level);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_context);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_context);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_context_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_netifcon);
+	SUITE_ADD_TEST(suite, test_cil_copy_netifcon_nested);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_netifcon);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_fill_context);
+	SUITE_ADD_TEST(suite, test_cil_copy_fill_context_anonrange);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_call);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_call);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_optional);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_optional);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_optional_merge);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_nodecon);
+	SUITE_ADD_TEST(suite, test_cil_copy_nodecon_anon);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_fill_ipaddr);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_ipaddr);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_ipaddr_dup_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_conditional);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_boolif);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_boolif);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_constrain);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_mlsconstrain);
+
+	//SUITE_ADD_TEST(suite, test_cil_copy_ast);
+	//SUITE_ADD_TEST(suite, test_cil_copy_ast_neg);
+	
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_orignull_neg);
+	SUITE_ADD_TEST(suite, test_cil_copy_node_helper_extraargsnull_neg);
+	
+	/* test_post.c */
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_not_b);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_b_not_a);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_type_atype_greater_btype);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_type_btype_greater_atype);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_stemlen_a_greater_b);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_stemlen_b_greater_a);
+	SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_equal);
+	
+	SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_atypestr_greater_btypestr);
+	SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_btypestr_greater_atypestr);
+	SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_apathstr_greater_bpathstr);
+	SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_bpathstr_greater_apathstr);
+	SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_equal);
+	
+	SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_a_greater_b);
+	SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_b_greater_a);
+	SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_equal);
+	
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_bipv6);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_bipv4);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_lessthan_bipv4);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_lessthan_bipv6);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6);
+	SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6);
+	
+	SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_type_a_greater_b);
+	SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_type_b_greater_a);
+	SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_fsstr_a_greater_b);
+	SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_fsstr_b_greater_a);
+	SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_equal);
+	
+	return suite;
+}
+
+CuSuite* CilTestFullCil(void) {
+	CuSuite* suite = CuSuiteNew();
+	SUITE_ADD_TEST(suite, test_min_policy);
+	SUITE_ADD_TEST(suite, test_integration);
+
+	return suite;
+}
diff --git a/libsepol/cil/test/unit/CilTest.h b/libsepol/cil/test/unit/CilTest.h
new file mode 100644
index 0000000..f43b0ed
--- /dev/null
+++ b/libsepol/cil/test/unit/CilTest.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CILTEST_H_
+#define CILTEST_H_
+
+#include "../../src/cil_tree.h"
+
+// TODO Check more in the data structures
+struct cil_file_data {
+	char *buffer;
+	uint32_t file_size;
+};
+
+void set_cil_file_data(struct cil_file_data **);
+void gen_test_tree(struct cil_tree **, char **);
+ 
+#endif
diff --git a/libsepol/cil/test/unit/CuTest.c b/libsepol/cil/test/unit/CuTest.c
new file mode 100644
index 0000000..9b481e3
--- /dev/null
+++ b/libsepol/cil/test/unit/CuTest.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ * 
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ * 
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ * 
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+	char* newStr = (char*) malloc( sizeof(char) * (size) );
+	return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+	int len = strlen(old);
+	char* newStr = CuStrAlloc(len + 1);
+	strcpy(newStr, old);
+	return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+	str->length = 0;
+	str->size = STRING_MAX;
+	str->buffer = (char*) malloc(sizeof(char) * str->size);
+	str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void)
+{
+	CuString* str = (CuString*) malloc(sizeof(CuString));
+	str->length = 0;
+	str->size = STRING_MAX;
+	str->buffer = (char*) malloc(sizeof(char) * str->size);
+	str->buffer[0] = '\0';
+	return str;
+}
+
+void CuStringDelete(CuString *str)
+{
+        if (!str) return;
+        free(str->buffer);
+        free(str);
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+	str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+	str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+	int length;
+
+	if (text == NULL) {
+		text = "NULL";
+	}
+
+	length = strlen(text);
+	if (str->length + length + 1 >= str->size)
+		CuStringResize(str, str->length + length + 1 + STRING_INC);
+	str->length += length;
+	strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+	char text[2];
+	text[0] = ch;
+	text[1] = '\0';
+	CuStringAppend(str, text);
+}
+
+__attribute__ ((format (printf, 2, 3))) void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+	va_list argp;
+	char buf[HUGE_STRING_LEN];
+	va_start(argp, format);
+	vsprintf(buf, format, argp);
+	va_end(argp);
+	CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+	int length = strlen(text);
+	if (pos > str->length)
+		pos = str->length;
+	if (str->length + length + 1 >= str->size)
+		CuStringResize(str, str->length + length + 1 + STRING_INC);
+	memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+	str->length += length;
+	memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+	t->name = CuStrCopy(name);
+	t->failed = 0;
+	t->ran = 0;
+	t->message = NULL;
+	t->function = function;
+	t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+	CuTest* tc = CU_ALLOC(CuTest);
+	CuTestInit(tc, name, function);
+	return tc;
+}
+
+void CuTestDelete(CuTest *t)
+{
+        if (!t) return;
+        free(t->name);
+        free(t);
+}
+
+void CuTestRun(CuTest* tc)
+{
+	jmp_buf buf;
+	tc->jumpBuf = &buf;
+	if (setjmp(buf) == 0)
+	{
+		tc->ran = 1;
+		(tc->function)(tc);
+	}
+	tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+	char buf[HUGE_STRING_LEN];
+
+	sprintf(buf, "%s:%d: ", file, line);
+	CuStringInsert(string, buf, 0);
+
+	tc->failed = 1;
+	tc->message = string->buffer;
+	if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+	CuString string;
+
+	CuStringInit(&string);
+	if (message2 != NULL) 
+	{
+		CuStringAppend(&string, message2);
+		CuStringAppend(&string, ": ");
+	}
+	CuStringAppend(&string, message);
+	CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+	if (condition) return;
+	CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 
+	const char* expected, const char* actual)
+{
+	CuString string;
+	if ((expected == NULL && actual == NULL) ||
+	    (expected != NULL && actual != NULL &&
+	     strcmp(expected, actual) == 0))
+	{
+		return;
+	}
+
+	CuStringInit(&string);
+	if (message != NULL) 
+	{
+		CuStringAppend(&string, message);
+		CuStringAppend(&string, ": ");
+	}
+	CuStringAppend(&string, "expected <");
+	CuStringAppend(&string, expected);
+	CuStringAppend(&string, "> but was <");
+	CuStringAppend(&string, actual);
+	CuStringAppend(&string, ">");
+	CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 
+	int expected, int actual)
+{
+	char buf[STRING_MAX];
+	if (expected == actual) return;
+	sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+	CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 
+	double expected, double actual, double delta)
+{
+	char buf[STRING_MAX];
+	if (fabs(expected - actual) <= delta) return;
+	sprintf(buf, "expected <%f> but was <%f>", expected, actual); 
+
+	CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 
+	void* expected, void* actual)
+{
+	char buf[STRING_MAX];
+	if (expected == actual) return;
+	sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+	CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+	testSuite->count = 0;
+	testSuite->failCount = 0;
+        memset(testSuite->list, 0, sizeof(testSuite->list));
+}
+
+CuSuite* CuSuiteNew(void)
+{
+	CuSuite* testSuite = CU_ALLOC(CuSuite);
+	CuSuiteInit(testSuite);
+	return testSuite;
+}
+
+void CuSuiteDelete(CuSuite *testSuite)
+{
+        unsigned int n;
+        for (n=0; n < MAX_TEST_CASES; n++)
+        {
+                if (testSuite->list[n])
+                {
+                        CuTestDelete(testSuite->list[n]);
+                }
+        }
+        free(testSuite);
+
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+	assert(testSuite->count < MAX_TEST_CASES);
+	testSuite->list[testSuite->count] = testCase;
+	testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+	int i;
+	for (i = 0 ; i < testSuite2->count ; ++i)
+	{
+		CuTest* testCase = testSuite2->list[i];
+		CuSuiteAdd(testSuite, testCase);
+	}
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+	int i;
+	for (i = 0 ; i < testSuite->count ; ++i)
+	{
+		CuTest* testCase = testSuite->list[i];
+		CuTestRun(testCase);
+		if (testCase->failed) { testSuite->failCount += 1; }
+	}
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+	int i;
+	for (i = 0 ; i < testSuite->count ; ++i)
+	{
+		CuTest* testCase = testSuite->list[i];
+		CuStringAppend(summary, testCase->failed ? "F" : ".");
+	}
+	CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+	int i;
+	int failCount = 0;
+
+	if (testSuite->failCount == 0)
+	{
+		int passCount = testSuite->count - testSuite->failCount;
+		const char* testWord = passCount == 1 ? "test" : "tests";
+		CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+	}
+	else
+	{
+		if (testSuite->failCount == 1)
+			CuStringAppend(details, "There was 1 failure:\n");
+		else
+			CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+		for (i = 0 ; i < testSuite->count ; ++i)
+		{
+			CuTest* testCase = testSuite->list[i];
+			if (testCase->failed)
+			{
+				failCount++;
+				CuStringAppendFormat(details, "%d) %s: %s\n",
+					failCount, testCase->name, testCase->message);
+			}
+		}
+		CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+		CuStringAppendFormat(details, "Runs: %d ",   testSuite->count);
+		CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+		CuStringAppendFormat(details, "Fails: %d\n",  testSuite->failCount);
+	}
+}
diff --git a/libsepol/cil/test/unit/CuTest.h b/libsepol/cil/test/unit/CuTest.h
new file mode 100644
index 0000000..c5ed90f
--- /dev/null
+++ b/libsepol/cil/test/unit/CuTest.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ * 
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ * 
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ * 
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+
+#define CUTEST_VERSION  "CuTest 1.5"
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE)		((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN	8192
+#define STRING_MAX		256
+#define STRING_INC		256
+
+typedef struct
+{
+	int length;
+	int size;
+	char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+void CuStringDelete(CuString* str);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+	char* name;
+	TestFunction function;
+	int failed;
+	int ran;
+	const char* message;
+	jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+void CuTestDelete(CuTest *t);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc, 
+	const char* file, int line, const char* message, 
+	const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc, 
+	const char* file, int line, const char* message, 
+	int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc, 
+	const char* file, int line, const char* message, 
+	double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc, 
+	const char* file, int line, const char* message, 
+	void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms)                        CuFail_Line(  (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond)                CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond)                CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac)           CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac)    CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac)           CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac)    CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl)        CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac)           CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac)    CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p)        CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES	1024
+
+#define SUITE_ADD_TEST(SUITE,TEST)	CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+	int count;
+	CuTest* list[MAX_TEST_CASES];
+	int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteDelete(CuSuite *testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
diff --git a/libsepol/cil/test/unit/test_cil.c b/libsepol/cil/test/unit/test_cil.c
new file mode 100644
index 0000000..7b57525
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_tree.h"
+
+void test_cil_symtab_array_init(CuTest *tc) {
+	struct cil_db *test_new_db;
+	test_new_db = malloc(sizeof(*test_new_db));
+
+	cil_symtab_array_init(test_new_db->symtab, cil_sym_sizes[CIL_SYM_ARRAY_ROOT]);
+	CuAssertPtrNotNull(tc, test_new_db->symtab);
+
+	free(test_new_db);
+}
+
+void test_cil_db_init(CuTest *tc) {
+	struct cil_db *test_db;
+
+	cil_db_init(&test_db);
+
+	CuAssertPtrNotNull(tc, test_db->ast);
+	CuAssertPtrNotNull(tc, test_db->symtab);
+	CuAssertPtrNotNull(tc, test_db->symtab);
+}
+
+// TODO: Reach SEPOL_ERR return in cil_db_init ( currently can't produce a method to do so )
+
+void test_cil_get_symtab_block(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->parent->flavor = CIL_BLOCK;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_class(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->parent->flavor = CIL_CLASS;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_root(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->parent->flavor = CIL_ROOT;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_flavor_neg(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->parent->flavor = 1234567;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertPtrEquals(tc, symtab, NULL);
+}
+
+void test_cil_get_symtab_null_neg(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = NULL;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertPtrEquals(tc, symtab, NULL);
+}
+
+void test_cil_get_symtab_node_null_neg(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_get_symtab(test_db, test_ast_node, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertPtrEquals(tc, symtab, NULL);
+	CuAssertPtrEquals(tc, test_ast_node, NULL);
+}
+
+void test_cil_get_symtab_parent_null_neg(CuTest *tc) {
+	symtab_t *symtab = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = NULL;
+	test_ast_node->line = 1;
+
+	int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertPtrEquals(tc, symtab, NULL);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil.h b/libsepol/cil/test/unit/test_cil.h
new file mode 100644
index 0000000..285b4ff
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_H_
+#define TEST_CIL_H_
+
+#include "CuTest.h"
+
+void test_cil_symtab_array_init(CuTest *);
+void test_cil_symtab_array_init_null_symtab_neg(CuTest *);
+void test_cil_db_init(CuTest *);
+void test_cil_get_symtab_block(CuTest *);
+void test_cil_get_symtab_class(CuTest *);
+void test_cil_get_symtab_root(CuTest *);
+void test_cil_get_symtab_flavor_neg(CuTest *);
+void test_cil_get_symtab_null_neg(CuTest *);
+void test_cil_get_symtab_node_null_neg(CuTest *);
+void test_cil_get_symtab_parent_null_neg(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_build_ast.c b/libsepol/cil/test/unit/test_cil_build_ast.c
new file mode 100644
index 0000000..f8cef71
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_build_ast.c
@@ -0,0 +1,19179 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_build_ast.h"
+
+#include "../../src/cil_build_ast.h"
+
+#include "../../src/cil_tree.h"
+
+int __cil_build_ast_node_helper(struct cil_tree_node *, uint32_t *, void *);
+int __cil_build_ast_last_child_helper(__attribute__((unused)) struct cil_tree_node *parse_current, void *);
+//int __cil_build_constrain_tree(struct cil_tree_node *parse_current, struct cil_tree_node *expr_root);
+
+struct cil_args_build {
+	struct cil_tree_node *ast;
+	struct cil_db *db;
+	struct cil_tree_node *macro;
+	struct cil_tree_node *tifstack;
+};
+
+struct cil_args_build *gen_build_args(struct cil_tree_node *node, struct cil_db *db, struct cil_tree_node * macro, struct cil_tree_node *tifstack)
+{
+	struct cil_args_build *args = cil_malloc(sizeof(*args));
+	args->ast = node;
+	args->db = db;
+	args->macro = macro;
+	args->tifstack = tifstack;
+
+	return args;
+}
+
+// First seen in cil_gen_common
+void test_cil_parse_to_list(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_avrule *test_avrule;
+	cil_avrule_init(&test_avrule);
+	test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+	test_avrule->src_str = cil_strdup(test_current->next->data);
+	test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+	cil_classpermset_init(&test_avrule->classpermset);
+
+	test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+	cil_permset_init(&test_avrule->classpermset->permset);
+
+	cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+
+	test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+	int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+	cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_parse_to_list_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_avrule *test_avrule;
+	cil_avrule_init(&test_avrule);
+	test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+	test_avrule->src_str = cil_strdup(test_current->next->data);
+	test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+	cil_classpermset_init(&test_avrule->classpermset);
+
+	test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+	cil_permset_init(&test_avrule->classpermset->permset);
+
+	cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+
+	test_current = NULL;
+
+	int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+	cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_parse_to_list_listnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_avrule *test_avrule;
+	cil_avrule_init(&test_avrule);
+	test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+	test_avrule->src_str = cil_strdup(test_current->next->data);
+	test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+	cil_classpermset_init(&test_avrule->classpermset);
+
+	test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+	cil_permset_init(&test_avrule->classpermset->permset);
+
+	test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+	int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+	cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_set_to_list(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	struct cil_list *cil_l = NULL;
+	struct cil_list *sub_list = NULL;
+
+	gen_test_tree(&test_tree, line);
+	cil_list_init(&cil_l);
+
+	int rc = cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+	sub_list = (struct cil_list *)cil_l->head->next->next->data;
+
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertStrEquals(tc, "foo1", (char*)cil_l->head->data);
+	CuAssertStrEquals(tc, "foo2", (char*)cil_l->head->next->data);
+	CuAssertStrEquals(tc, "foo3", (char*)sub_list->head->data);
+}
+
+void test_cil_set_to_list_tree_node_null_neg(CuTest *tc) {
+	struct cil_list *cil_l = NULL;
+	int rc = cil_set_to_list(NULL, cil_l, 1);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_set_to_list_cl_head_null_neg(CuTest *tc) {
+	char *line[] = {"(", "foo", "bar", ")", NULL};
+
+	struct cil_list *cil_l;
+	struct cil_tree *test_tree = NULL;
+
+	cil_list_init(&cil_l);
+	gen_test_tree(&test_tree, line);
+	test_tree->root->cl_head = NULL;
+
+	int rc = cil_set_to_list(test_tree->root, cil_l, 1);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_set_to_list_listnull_neg(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", "foo3", ")", NULL};
+
+	struct cil_tree *test_tree = NULL;
+	gen_test_tree(&test_tree, line);
+
+	int rc = cil_set_to_list(test_tree->root, NULL, 1);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, ((struct cil_block*)test_ast_node->data)->is_abstract, 0);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BLOCK);
+}
+
+void test_cil_gen_block_justblock_neg(CuTest *tc) {
+	char *line[] = {"(", "block", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_treenull_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_tree->root->cl_head->cl_head = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_nodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_nodeparentnull_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = NULL;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_destroy_block(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+
+	cil_destroy_block((struct cil_block*)test_ast_node->data);
+	CuAssertPtrEquals(tc, NULL,test_ast_node->data);
+}
+
+void test_cil_gen_blockinherit(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_blockinherit_namelist_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_namenull_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_class *new_node;
+	cil_class_init(&new_node);
+
+	struct cil_tree_node *new_tree_node;
+	cil_tree_node_init(&new_tree_node);
+	new_tree_node->data = new_node;
+	new_tree_node->flavor = CIL_CLASS;
+
+	test_ast_node->parent = new_tree_node;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+	int rc1 = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next, test_ast_node);
+	int rc2 = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next->next, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_gen_perm_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	int rc = 0;
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current_perm = NULL;
+	struct cil_tree_node *test_new_ast = NULL;
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	test_current_perm = test_tree->root->cl_head->cl_head->next->next->cl_head;
+
+	cil_tree_node_init(&test_new_ast);
+	test_new_ast->parent = test_ast_node;
+	test_new_ast->line = test_current_perm->line;
+
+	rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	int rc = 0;
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current_perm = NULL;
+	struct cil_tree_node *test_new_ast = NULL;
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_current_perm = NULL; 
+
+	cil_tree_node_init(&test_new_ast);
+	test_new_ast->parent = test_ast_node;
+
+	rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_class *new_node;
+	cil_class_init(&new_node);
+
+	struct cil_tree_node *new_tree_node;
+	cil_tree_node_init(&new_tree_node);
+	new_tree_node->data = new_node;
+	new_tree_node->flavor = CIL_CLASS;
+
+	int rc = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_nodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	int rc = 0;
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_current_perm = NULL;
+	struct cil_tree_node *test_new_ast = NULL;
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_current_perm = test_tree->root->cl_head->cl_head->next->next->cl_head;
+
+	cil_tree_node_init(&test_new_ast);
+	test_new_ast->parent = test_ast_node;
+	test_new_ast->line = test_current_perm->line;
+
+	rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_permset_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "(", "foo", ")", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_noperms_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_emptyperms_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_nodes(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	char *test_key = test_tree->root->cl_head->cl_head->next->data;
+	struct cil_class *test_cls;
+	cil_class_init(&test_cls);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+	test_ast_node->data = test_cls;
+	test_ast_node->flavor = CIL_CLASS;
+
+	int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_perm_nodes_failgen_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	char *test_key = test_tree->root->cl_head->cl_head->next->data;
+	struct cil_class *test_cls;
+	cil_class_init(&test_cls);
+
+	cil_symtab_destroy(&test_cls->perms);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+	test_ast_node->data = test_cls;
+	test_ast_node->flavor = CIL_CLASS;
+
+	int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+	CuAssertIntEquals(tc, SEPOL_ENOMEM, rc);
+}
+
+void test_cil_gen_perm_nodes_inval_perm_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "(", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	char *test_key = test_tree->root->cl_head->cl_head->next->data;
+	struct cil_class *test_cls;
+	cil_class_init(&test_cls);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+	test_ast_node->data = test_cls;
+	test_ast_node->flavor = CIL_CLASS;
+
+	int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset(CuTest *tc) { 
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_permset *permset;
+	cil_permset_init(&permset);
+
+	int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_permset_sublist_neg(CuTest *tc) { 
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_permset *permset;
+	cil_permset_init(&permset);
+
+	int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset_startpermnull_neg(CuTest *tc) { 
+	char *line[] = {"(", "permissionset", "foo", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_permset *permset;
+	cil_permset_init(&permset);
+
+	int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset_permsetnull_neg(CuTest *tc) { 
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_permset *permset = NULL;
+
+	int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in(CuTest *tc) { 
+	char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_in_blockstrnull_neg(CuTest *tc) { 
+	char *line[] = {"(", "in", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_extra_neg(CuTest *tc) { 
+	char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", "extra", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_dbnull_neg(CuTest *tc) { 
+	char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_currnull_neg(CuTest *tc) { 
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_astnull_neg(CuTest *tc) { 
+	char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class(CuTest *tc) { 
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->cl_tail);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_CLASS);
+}
+
+void test_cil_gen_class_noname_neg(CuTest *tc) { 
+	char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_nodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_tree->root->cl_head->cl_head = NULL;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noclass_neg(CuTest *tc) { 
+	char *line[] = {"(", "test", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noclassname_neg(CuTest *tc) { 
+	char *line[] = {"(", "class", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_namesublist_neg(CuTest *tc) { 
+	char *line[] = {"(", "class", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noperms(CuTest *tc) { 
+	char *line[] = {"(", "class", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_class_permsnotinlist_neg(CuTest *tc) { 
+	char *line[] = {"(", "class", "foo", "read", "write", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_extrapermlist_neg(CuTest *tc) { 
+	char *line[] = {"(", "class", "foo", "(", "read", ")", "(", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_listinlist_neg(CuTest *tc) { 
+        char *line[] = {"(", "class", "test", "(", "read", "(", "write", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_anonperms(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_classpermset_anonperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", "(", "extra", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_namedperms(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "perms", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_classpermset_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", "extra", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_emptypermslist_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_noperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_classnodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_cpsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_classpermset *cps = NULL;
+
+	int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classpermset_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "(", "foo", ")", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_noperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", "char", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_emptyperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_classmap *map = NULL;
+	cil_classmap_init(&map);	
+
+	test_ast_node->flavor = CIL_CLASSMAP;
+	test_ast_node->data = map;
+	
+	struct cil_tree_node *test_ast_node_a;
+	cil_tree_node_init(&test_ast_node_a);
+
+	test_ast_node_a->parent = test_ast_node;
+	test_ast_node_a->line = test_tree->root->cl_head->cl_head->next->next->cl_head->line;
+	test_ast_node_a->path = test_tree->root->cl_head->cl_head->next->next->cl_head->path;
+	
+	int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmap_perm_dupeperm_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_ast_node_a;
+	cil_tree_node_init(&test_ast_node_a);
+
+	test_ast_node_a->parent = test_ast_node;
+	test_ast_node_a->line = test_tree->root->cl_head->cl_head->next->next->cl_head->line;
+	test_ast_node_a->path = test_tree->root->cl_head->cl_head->next->next->cl_head->path; 
+	
+	int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+	CuAssertIntEquals(tc, SEPOL_EEXIST, rc);
+}
+
+void test_cil_gen_classmap_perm_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_ast_node_a;
+	cil_tree_node_init(&test_ast_node_a);
+
+	test_ast_node_a->parent = test_ast_node;
+	test_ast_node_a->line = test_tree->root->cl_head->cl_head->line;
+	test_ast_node_a->path = test_tree->root->cl_head->cl_head->path;
+
+	test_db = NULL;
+
+	int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_ast_node_a;
+	cil_tree_node_init(&test_ast_node_a);
+
+	test_ast_node_a->parent = test_ast_node;
+	test_ast_node_a->line = test_tree->root->cl_head->cl_head->line;
+	test_ast_node_a->path = test_tree->root->cl_head->cl_head->path;
+
+	int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_ast_node_a = NULL;
+
+	int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmap_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_emptyperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_anonpermset(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", 
+			"(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmapping_anonpermset_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", 
+			"(", "file", "(", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_namedpermset(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmapping_noclassmapname_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_noclassmapperm_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_nopermissionsets_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", 
+			"(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", 
+			"(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_COMMON);
+}
+
+void test_cil_gen_common_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "common", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_twoperms_neg(CuTest *tc) {
+	char *line[] = {"(", "common", "foo", "(", "write", ")", "(", "read", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_permsublist_neg(CuTest *tc) {
+        char *line[] = {"(", "common", "test", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_noperms_neg(CuTest *tc) {
+        char *line[] = {"(", "common", "test", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+       
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid(CuTest *tc) {
+	char *line[] = {"(", "sid", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_sid_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", "foo", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SIDCONTEXT);
+}
+
+void test_cil_gen_sidcontext_namedcontext(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "something", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SIDCONTEXT);
+}
+
+void test_cil_gen_sidcontext_halfcontext_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_empty_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_dblname_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "test2", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_pcurrnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_astnodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, NULL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE);
+}
+
+void test_cil_gen_type_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", "bar," ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattribute(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "test", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPEATTRIBUTE);
+}
+
+void test_cil_gen_typeattribute_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_typeattribute_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_typeattribute_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattribute_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "foo", "bar," ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_typebounds_notype1_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_type1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "(", "type_a", ")", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_notype2_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_type2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", "(", "type_b", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", "type_b", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_typepermissive_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_typeinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "(", "type_a", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "type_a", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+	
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nametypetransition_strinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "(", "str", ")", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nostr_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_srcinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "(", "foo", ")", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nosrc_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_tgtinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "(", "bar", ")", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_notgt_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_classinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "(", "file", ")", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_destinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "(", "foobar", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nodest_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_nametypetransition_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_namedtransition(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "namedtrans", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_low_l(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "(", "s0", "(", "c0", ")", ")", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_low_l_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "(", "s0", "(", ")", ")", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_anon_high_l(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "(", "s0", "(", "c0", ")",  ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_high_l_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "(", "s0", "(", ")",  ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nofirsttype_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_firsttype_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "(", "type_a_t", ")", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nosecondtype_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_secondtype_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "(", "type_b_t", ")", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_class_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "(", "class", ")", "(", "low_l", "high_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nolevel_l_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nolevel_h_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_and(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_or(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "or", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_xor(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "xor", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_not(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "not", "foo", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_not_noexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "not", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_not_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "not", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_eq(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "eq", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_neq(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "neq", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_nested(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "or", "(","neq", "foo", "bar", ")", "(", "eq", "baz", "boo", ")", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_nested_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "(","neq", "foo", "bar", ")", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_nested_emptyargs_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "eq", "(", ")", "(", ")", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_nested_missingoperator_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "or", "(","foo", "bar", ")", "(", "eq", "baz", "boo", ")", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_arg1null_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "eq", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_arg2null_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "eq", "foo", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_extraarg_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "eq", "foo", "bar", "extra", ")",
+			"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_booleanif *bif;
+	cil_boolif_init(&bif);
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_stacknull_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "xor", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, NULL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_true(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_false(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+			"(", "false", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_unknowncond_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+			"(", "dne", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_true(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_false(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "false", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_unknowncond_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "dne", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nested(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_nested_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "(", "or", "foo", "bar", ")", "baz", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "(", "or", "foo", "bar", ")", "baz", "beef", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_extra_parens_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "(", "or", "foo", "bar", ")", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nocond(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "baz",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "**", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nocond_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_notruelist_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_empty_cond_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_true(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", 
+			"(", "true", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_false(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+			"(", "false", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_unknowncond_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+			"(", "dne", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_true(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_false(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "false", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_unknowncond_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "dne", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_nocond(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "baz",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_nested(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_nested_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "(", "or", "foo", "bar", ")", "baz", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", "beef", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_extra_parens_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "(", "or", "foo", "bar", ")", ")",
+			"(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "**", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_nocond_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_notruelist_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_true(CuTest *tc) {
+	char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_condblock_false(CuTest *tc) {
+	char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_condblock_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_nocond_neg(CuTest *tc) {
+	char *line[] = {"(", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", "Extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertStrEquals(tc, ((struct cil_typealias*)test_ast_node->data)->type_str, test_tree->root->cl_head->cl_head->next->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPEALIAS);
+}
+
+void test_cil_gen_typealias_incomplete_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_incomplete_neg2(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_extratype_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "foo", "extra_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "test_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_and_two_types(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "and", "test_t", "test2_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_not(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "notypes_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_exclude_attr(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "attr", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_exclude_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "type_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "(", "filetypes", ")", "(", "test_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_emptylists_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_listinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "(", "test_t", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "test_t", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userbounds(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_gen_userbounds_notype1_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_type1_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "(", "user1", ")", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_notype2_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_type2_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "(", "user2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "user2", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_role(CuTest *tc) {
+	char *line[] = {"(", "role", "test_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLE);
+}
+
+void test_cil_gen_role_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "test_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "test_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_extrarole_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "test_r", "extra_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "role", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r",  "bar_t", "process",  "foobar_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLETRANSITION);
+}
+
+void test_cil_gen_roletransition_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletransition(NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc); 	
+}
+
+void test_cil_gen_roletransition_astnull_neg (CuTest *tc) {
+	char *line[] = {"(", "roletransition" "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct  cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_srcnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_tgtnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_resultnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_true(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 1);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BOOL);
+}
+
+void test_cil_gen_bool_tunable_true(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_TUNABLE);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 1);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TUNABLE);
+}
+
+void test_cil_gen_bool_false(CuTest *tc) {
+	char *line[] = {"(", "boolean", "bar", "false", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 0);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BOOL);
+}
+
+void test_cil_gen_bool_tunable_false(CuTest *tc) {
+	char *line[] = {"(", "tunable", "bar", "false", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_TUNABLE);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 0);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TUNABLE);
+}
+
+void test_cil_gen_bool_none_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_notbool_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_boolname_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_extraname_false_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "false", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_extraname_true_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1type(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1t1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "t1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t2type(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t2", "type_t", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t2t2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t2", "t2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1role(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "role_r", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1r1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r2role(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r2", "role_r", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r2r2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r2", "r2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1t2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "t2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_r1r2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1r2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1u2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "u2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1user(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "user_u", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1u1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "u1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u2user(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u2", "user_u", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u2u2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u2", "u2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l2h2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1h1(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "h1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1h2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1l2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "l2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1h2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "l1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg(CuTest *tc) {
+	char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_CONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg(CuTest *tc) {
+	char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_CONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h2", "h1", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", "neq", "l2", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_noexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_emptyparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_extraparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", "neq", "l2", "h2", ")", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", 
+			"(", "neq", "l1", "l2", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", 
+			"(", "foo", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_noexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", "(", "foo", ")", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", 
+			"(", "neq", "l1", "l2", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", 
+			"(", "foo", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_noexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", "(", "foo", ")", "(", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l2", "h2", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "(", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l1", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l1", "(", "h2", ")", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "foo", "foo", "extra", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_stacknull_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, NULL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_operatorinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "(", "eq", ")", "t1", "type_t", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incorrectcall_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *cons;
+	cil_constrain_init(&cons);
+	cil_classpermset_init(&cons->classpermset);
+	cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+	
+	int rc = cil_gen_expr_stack(parse_current->next->next->cl_head->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "staff_r", "sysadm_r", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertStrEquals(tc, ((struct cil_roleallow*)test_ast_node->data)->src_str, test_current->next->data);
+	CuAssertStrEquals(tc, ((struct cil_roleallow*)test_ast_node->data)->tgt_str, test_current->next->next->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLEALLOW);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_roleallow_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_roleallow(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc); 
+}
+
+void test_cil_gen_roleallow_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_srcnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_tgtnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "roleallow", "foo", "bar", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rolebounds(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_gen_rolebounds_norole1_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_role1_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "(", "role1", ")", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_norole2_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_role2_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "(", "role2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "role2", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_avrule(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->src_str, test_current->next->data);
+	CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->tgt_str, test_current->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->classpermset->class_str, test_current->next->next->next->cl_head->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_AVRULE);
+	CuAssertPtrNotNull(tc, ((struct cil_avrule*)test_ast_node->data)->classpermset->permset->perms_list_str);
+
+	struct cil_list_item *test_list = ((struct cil_avrule*)test_ast_node->data)->classpermset->permset->perms_list_str->head;
+	test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+	while(test_list != NULL) {
+	    CuAssertIntEquals(tc, test_list->flavor, CIL_AST_STR);
+	    CuAssertStrEquals(tc, test_list->data, test_current->data );
+	    test_list = test_list->next;
+	    test_current = test_current->next;
+	}
+}
+
+void test_cil_gen_avrule_permset(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "permset", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_avrule_permset_anon(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_avrule_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "permset", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourceparens(CuTest *tc) {
+	char *line[] = {"(", "allow", "(", "test", ")", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourceemptyparen_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "(", ")", "bar", "file", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetparens(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "(", "foo", ")", "bar", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetemptyparen_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "bar", "(", ")", "file", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "bar", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourcedomainnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetdomainnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_objectclassnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_permsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "foo", "bar", "(", "baz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_twolists_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "bar", "(", "write", ")", "(", "read", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+	CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_transition_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc); 
+}
+
+void test_cil_gen_type_rule_transition_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}	
+
+void test_cil_gen_type_rule_transition_srcnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+	
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_tgtnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_objnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_resultnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+	CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_change_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc); 
+}
+
+void test_cil_gen_type_rule_change_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}	
+
+void test_cil_gen_type_rule_change_srcnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+	
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_tgtnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_objnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_resultnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+	CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+	CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_member_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc); 
+}
+
+void test_cil_gen_type_rule_member_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}	
+
+void test_cil_gen_type_rule_member_srcnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+	
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_tgtnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_objnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_resultnull_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user(CuTest *tc) {
+	char *line[] = {"(", "user", "sysadm", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, CIL_USER, test_ast_node->flavor);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertPtrEquals(tc, test_ast_node, ((struct cil_symtab_datum*)test_ast_node->data)->node);
+	CuAssertStrEquals(tc, test_tree->root->cl_head->cl_head->next->data, ((struct cil_symtab_datum*)test_ast_node->data)->name);
+}
+
+void test_cil_gen_user_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "user", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "user", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_nouser_neg(CuTest *tc) {
+	char *line[] = {"(", "user", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_xsinfo_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "sysadm", "xsinfo", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", "lvl_l", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userlevel_anon_level(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userlevel_anon_level_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", "(", "s0", "(", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_usernull_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_userrange_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "(", "user", ")", "level", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_levelnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_levelrangeempty_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", "(", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user_u", "level", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user", "level", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "user", "level", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_named(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", "range", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrange_anon(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", "(", "low", "high", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrange_usernull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonuser_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "(", "user_u", ")", "(", "low", "high", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_rangenamenull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonrangeinvalid_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", "(", "low", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonrangeempty_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", "(", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user_u", "(", "low", "high", ")", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user", "range", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "user", "range", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_ast_node->data);
+	CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SENS);
+
+}
+
+void test_cil_gen_sensitivity_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db = NULL;
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_sensitivity(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_sensnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_senslist_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "(", "s0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", "extra", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}	
+
+void test_cil_gen_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_sensalias_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_currnull_neg(CuTest *tc) {
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_sensalias(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init (&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_sensnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_senslist_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "(", "s0", "s1", ")", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_aliasnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_aliaslist_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "(", "alias", "alias2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_category_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_category(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_catnull_neg(CuTest *tc){
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_catlist_neg(CuTest *tc){
+	char *line[] = {"(", "category", "(", "c0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catset_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+	
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_namenull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_setnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_namelist_neg(CuTest *tc) { //This should fail before gen_node call - additional syntax checks are needed
+	char *line[] = {"(", "categoryset", "(", "somecats", ")", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", "extra",  ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_notset_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "blah", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+// TODO: This doesn't actually test failure of gen_node 
+void test_cil_gen_catset_nodefail_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_settolistfail_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catalias_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catalias(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_catnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_aliasnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root->cl_head->cl_head->next->next = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catrange_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_norange_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_emptyrange_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_extrarange_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catrange(test_db, NULL, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype(CuTest *tc) {
+	char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_roletype_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_roletype_empty_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_rolelist_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", "(", "admin_r", ")", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+// TODO
+// Not sure this is actually testing roletype
+// I think this will just test that type is null
+void test_cil_gen_roletype_roletype_sublist_neg(CuTest *tc) {
+	char *line[] = {"(", "(", "roletype", "admin_r", ")", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_typelist_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", "admin_r", "(", "admin_t", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrole_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_empty_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_userlist_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", "(", "staff_u", ")", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+//TODO: see above
+void test_cil_gen_userrole_userrole_sublist_neg(CuTest *tc) {
+	char *line[] = {"(", "(", "userrole", "staff_u", ")", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_rolelist_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "(", "staff_r", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        char *test_key = test_tree->root->cl_head->cl_head->next->data;
+        struct cil_class *test_cls;
+		cil_class_init(&test_cls);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+        test_ast_node->data = test_cls;
+        test_ast_node->flavor = CIL_CLASS;
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classcommon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_missingclassname_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_noperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        char *test_key = test_tree->root->cl_head->cl_head->next->data;
+        struct cil_class *test_cls;
+		cil_class_init(&test_cls);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+        test_ast_node->data = test_cls;
+        test_ast_node->flavor = CIL_CLASS;
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_extraperms_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", "file", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        char *test_key = test_tree->root->cl_head->cl_head->next->data;
+        struct cil_class *test_cls;
+		cil_class_init(&test_cls);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+        test_ast_node->data = test_cls;
+        test_ast_node->flavor = CIL_CLASS;
+
+        int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catorder_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db = NULL;
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node = NULL;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_missingcats_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_nosublist_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "c0", "c255", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_nestedcat_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "(", "c255", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "sensitivity", "s2", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_dominance_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_nosensitivities_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_nosublist_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "s0", "s2", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_senscat_nosublist(CuTest *tc) {
+	char *line[] = {"(", "sensitivitycategory", "s1", "c0", "c255", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_senscat_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_nosensitivities_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_sublist_neg(CuTest *tc) {
+      char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "(", "c255", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_nocat_neg(CuTest *tc) {
+      char *line[] = {"(", "sensitivitycategory", "s1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_level *test_level;
+	cil_level_init(&test_level);
+
+        int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_level_sensnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_level *test_level;
+	cil_level_init(&test_level);
+
+        int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next, test_level);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level_levelnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_level *test_level = NULL;
+
+        int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level_nocat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_level *test_level;
+	cil_level_init(&test_level);
+
+        int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_level_emptycat_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_level *test_level;
+	cil_level_init(&test_level);
+
+        int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_level_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "level", "(", "low", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_emptysensparens_neg(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", "s0", "(", "c0", ")", ")", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_emptycat_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_nosens_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_levelrange_rangeinvalid_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", "extra", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_namenull_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_rangenull_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_rangeempty_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", "extra", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dne", "l1", "l2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_noperm_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_noclass_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_noperm_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expression_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+        int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_context_unnamedlvl(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "(", "s0", ")", "(", "s0", ")", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+        int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_context_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context = NULL;
+
+        int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nouser_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_norole_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_notype_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nolowlvl_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nohighlvl_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "(", "low", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_unnamedlvl_nocontextlow_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "(", "s0", "(", ")", ")", "high", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_unnamedlvl_nocontexthigh_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "low", "(", "s0", "(", ")", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_context *test_context;
+	cil_context_init(&test_context);
+
+	int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_context_notinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_extralevel_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", "extra", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_emptycontext_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", "(", "extra", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_doubleparen_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "(", "system_u", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_norole_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_roleinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "(", "role_r", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_notype_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_typeinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "(", "type_t", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nolevels_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "type_t", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nosecondlevel_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "type_t", "(", "low", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "context", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nouser_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "s0", ")", "(", "s0", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "system_u", "object_r", "node_lo_t", "(", "s0", ")", "(", "s0", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_dir(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "dir", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_file(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_char(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "char", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_block(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "block", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_socket(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "socket", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_pipe(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "pipe", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_symlink(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "symlink", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_any(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "any", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "dne", "context", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL; 
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str1null_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str1_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "(", "root", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str2null_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str2_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "(", "path", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_classnull_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_class_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "(", "file", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_contextnull_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "context", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_udp(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "80", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_tcp(CuTest *tc) {
+	char *line[] = {"(", "portcon", "tcp", "80", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_unknownprotocol_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "unknown", "80", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "80", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_portrange(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "25", "75", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_portrange_one_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "0", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_portrange_morethanone_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "0", "1", "2", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_singleport_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "foo", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_lowport_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "foo", "90", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_highport_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "80", "foo", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "0", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "(", "0", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_str1null_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_str1parens_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "(", "80", ")", "port", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_portnull_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_contextnull_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "port", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "80", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "80", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_nodecon *nodecon;
+	cil_nodecon_init(&nodecon);
+	cil_ipaddr_init(&nodecon->addr);
+
+        int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_ipaddr_addrnodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_nodecon *nodecon;
+	cil_nodecon_init(&nodecon);
+	cil_ipaddr_init(&nodecon->addr);
+
+        int rc = cil_fill_ipaddr(NULL, nodecon->addr);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_addrnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_nodecon *nodecon;
+	cil_nodecon_init(&nodecon);
+	nodecon->addr = NULL;
+
+        int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_addrinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "(", "192.168.1.1", ")", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_nodecon *nodecon;
+	cil_nodecon_init(&nodecon);
+	cil_ipaddr_init(&nodecon->addr);
+
+        int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", "extra", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	struct cil_nodecon *nodecon;
+	cil_nodecon_init(&nodecon);
+	cil_ipaddr_init(&nodecon->addr);
+
+        int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_ipnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_ipanon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_ipanon_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.1.1", ")", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_netmasknull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_netmaskanon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "(", "255.255.255.4", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_netmaskanon_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "(", "str0", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_contextnull_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "type_t", "(", "low", "high", ")", ")", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_genfscon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_genfscon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_typenull_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_typeparens_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "(", "type", ")", "path", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_pathnull_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_pathparens_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "(", "path", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_contextnull_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_netifcon_nested(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_netifcon_nested_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "(", "eth1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_emptysecondlist_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_extra_nested_secondlist_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "extra",  
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", "foo", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_missingobjects_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", ")",
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_secondnested_missingobjects_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", "system_u", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_ethmissing_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_interfacemissing_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_packetmissing_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_pirqcon_pirqnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "notint", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_nopirq_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_pirqrange_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "(", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_anoncontext_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "(", "con", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", "1", "2", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_firstnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", "foo", "2", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_secondnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", "1", "foo", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_empty_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_singleiomem_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "(", "1", "2", "3", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "notint", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_noiomem_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_anoncontext_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "(", "con", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", "1", "2", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_firstnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", "foo", "2", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_secondnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", "1", "foo", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_empty_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_singleioport_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "(", "1", "2", "3", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportnotint_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "notint", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_noioport_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_anoncontext_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "(", "con", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_pcidevicecon_pcidevicenotint_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "notint", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_nopcidevice_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_pcidevicerange_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "(", "1", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_anoncontext_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "(", "con", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_anoncontext(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_anoncontext_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "(", "system_u", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_xattr(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_task(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "task", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_transition(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "trans", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_invalidtype_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "foo", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_notype_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_typeinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "(", "xattr", ")", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_nofilesystem_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_filesysteminparens_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "(", "ext3", ")", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_emptyconparens_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "con", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparams(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", ")", "(", "type", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_type(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_role(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "role", "a", ")", ")", "(", "role", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_user(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "user", "a", ")", ")", "(", "user", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_sensitivity(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")", "(", "sensitivity", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_category(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "category", "a", ")", ")", "(", "category", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_catset(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "categoryset", "a", ")", ")", "(", "categoryset", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_level(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "level", "a", ")", ")", "(", "level", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_class(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "class", "a", ")", ")", "(", "class", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_classmap(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "classmap", "a", ")", ")", "(", "classmap", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_permset(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")", 
+				"(", "allow", "foo", "bar", "baz", "a", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_duplicate(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "class", "a",")", "(", "class", "x", ")", ")", "(", "class", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_duplicate_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "class", "a",")", "(", "class", "a", ")", ")", "(", "class", "b", "(", "read," ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_unknown_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node = NULL;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_unnamed_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparam_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_nosecondparam_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparam_name_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_emptyparam_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_paramcontainsperiod_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a.", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_noargs(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_anon(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_empty_call_neg(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_name_inparens_neg(CuTest *tc) {
+	char *line[] = {"(", "call", "(", "mm", ")", "(", "foo", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "call", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_optional_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_unnamed_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", "(", "opt", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_emptyoptional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_optional_norule_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap(CuTest *tc) {
+	char *line[] = {"(", "policycap", "open_perms", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_policycap_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", "(", "pol", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", "pol", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipv4(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ipaddr_ipv4_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", ".168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipv6(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ipaddr_ipv6_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "2001:0db8:85a3:0000:0000:8a2e:0370:::7334", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_noname_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_nameinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "(", "ip", ")", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_noip_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipinparens_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "(", "192.168.1.1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_extra_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", "extra", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db = NULL;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_currnull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node = NULL;
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+        CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+/*
+	cil_build_ast test cases
+*/
+
+void test_cil_build_ast(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_dbnull_neg(CuTest *tc) {
+	char *line[] = {"(", "test", "\"qstring\"", ")", ";comment", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *null_db = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_build_ast(null_db, test_tree->root, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_astnull_neg(CuTest *tc) {
+	char *line[] = {"(", "test", "\"qstring\"", ")", ";comment", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_db->ast->root = NULL;
+
+	int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_suberr_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "test", "(", "block", "(", "type", "log", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_treenull_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "bar", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	test_tree->root = NULL;
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_db->ast->root = NULL;
+
+	int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+	
+void test_cil_build_ast_node_helper_block(CuTest *tc) {
+	char *line[] = {"(", "block", "test", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_block_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_blockinherit(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_blockinherit_neg(CuTest *tc) {
+	char *line[] = {"(", "blockinherit", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_permset(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, CIL_TREE_SKIP_NEXT, finished);
+}
+
+void test_cil_build_ast_node_helper_permset_neg(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_in(CuTest *tc) {
+	char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_in_neg(CuTest *tc) {
+	char *line[] = {"(", "in", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_class(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_class_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_classpermset(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, CIL_TREE_SKIP_NEXT, finished);
+}
+
+void test_cil_build_ast_node_helper_classpermset_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_classmap(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_classmap_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_classmapping(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_classmapping_neg(CuTest *tc) {
+	char *line[] = {"(", "classmapping", "files", "read", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_common(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_common_neg(CuTest *tc) {
+	char *line[] = {"(", "common", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sid(CuTest *tc) {
+	char *line[] = {"(", "sid", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_sid_neg(CuTest *tc) {
+	char *line[] = {"(", "sid", "(", "blah", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_sidcontext_neg(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "(", "blah", "blah", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_user(CuTest *tc) {
+	char *line[] = {"(", "user", "jimmypage", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_user_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "foo", "bar", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userlevel(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "johnpauljones", "level", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_userlevel_neg(CuTest *tc) {
+	char *line[] = {"(", "userlevel", "johnpauljones", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userrange(CuTest *tc) {
+	char *line[] = {"(", "userrange", "johnpauljones", "range", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_userrange_neg(CuTest *tc) {
+	char *line[] = {"(", "userrange", "johnpauljones", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_neg(CuTest *tc) {
+	char *line[] = {"(", "type", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_attribute(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_attribute_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typebounds(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "foo", "bar", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typebounds_neg(CuTest *tc) {
+	char *line[] = {"(", "typebounds", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_typepermissive(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", "foo", ")", NULL};
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typepermissive_neg(CuTest *tc) {
+	char *line[] = {"(", "typepermissive", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_nametypetransition(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_nametypetransition_neg(CuTest *tc) {
+	char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_rangetransition(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", "type_a", "type_b", "class", "(", "low_l", "high_l", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_rangetransition_neg(CuTest *tc) {
+	char *line[] = {"(", "rangetransition", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_boolif(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_boolif_neg(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "*&", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_condblock_true(CuTest *tc) {
+	char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "write", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_true_neg(CuTest *tc) {
+	char *line[] = {"(", "true", "(", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_condblock_false(CuTest *tc) {
+	char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "write", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_false_neg(CuTest *tc) {
+	char *line[] = {"(", "false", "(", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_tunif(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_tunif_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "*&", "foo", "bar", ")",
+			"(", "allow", "foo", "bar", "read", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}	
+
+void test_cil_build_ast_node_helper_typealias(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typealias_notype_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattribute(CuTest *tc)
+{
+	char *line[] = {"(", "typeattribute", "type", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattribute_neg(CuTest *tc)
+{
+	char *line[] = {"(", "typeattribute", ".fail.type", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattributeset(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "filetypes", "(", "and", "test_t", "test2_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattributeset_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattributeset", "files", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userbounds(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userbounds_neg(CuTest *tc) {
+	char *line[] = {"(", "userbounds", "user1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_role(CuTest *tc) {
+	char *line[] = {"(", "role", "test_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_role_neg(CuTest *tc) {
+	char *line[] = {"(", "role", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletransition(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletransition_neg(CuTest *tc) {
+	char *line[] = {"(", "roletransition", "foo_r", "bar_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roleallow(CuTest *tc) {
+        char *line[] = {"(", "roleallow", "staff_r", "sysadm_r", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roleallow_neg(CuTest *tc) {
+        char *line[] = {"(", "roleallow", "staff_r", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_rolebounds(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_rolebounds_neg(CuTest *tc) {
+	char *line[] = {"(", "rolebounds", "role1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_allow(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_allow_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_auditallow(CuTest *tc) {
+	char *line[] = {"(", "auditallow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_auditallow_neg(CuTest *tc) {
+	char *line[] = {"(", "auditallow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_dontaudit(CuTest *tc) {
+	char *line[] = {"(", "dontaudit", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_dontaudit_neg(CuTest *tc) {
+	char *line[] = {"(", "dontaudit", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_neverallow(CuTest *tc) {
+	char *line[] = {"(", "neverallow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_neverallow_neg(CuTest *tc) {
+	char *line[] = {"(", "neverallow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_transition(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_transition_neg(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", "extra",  ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_change(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_change_neg(CuTest *tc) {
+	char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", "extra",  ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_member(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_member_neg(CuTest *tc) {
+	char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", "extra",  ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);	
+	
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_tunable(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_tunable_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensitivity(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensitivity_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensalias_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_category(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_category_neg(CuTest *tc) {
+	char *line[] = {"(", "category", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catset(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished); 
+}
+
+void test_cil_build_ast_node_helper_catset_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished); 
+}
+
+void test_cil_build_ast_node_helper_catorder(CuTest *tc) {
+	char *line[] = {"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished); 
+}
+
+void test_cil_build_ast_node_helper_catorder_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryorder", "c0", "c1", "c2", "extra", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished); 
+}
+
+void test_cil_build_ast_node_helper_catalias(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catalias_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "range", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catrange(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_catrange_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryrange", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletype(CuTest *tc) {
+	char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_roletype_neg(CuTest *tc) {
+	char *line[] = {"(", "roletype", "(", "admin_r", ")", "admin_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+	
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_userrole(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_userrole_neg(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "(", "staff_r", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_classcommon(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "foo", "foo", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_classcommon_neg(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "staff_u", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_dominance(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "sensitivity", "s2", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_dominance_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "sensitivity", "s2", ")",
+                        "(", "dominance", "(", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->next->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_senscat_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->next->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_level(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_level_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_levelrange(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_levelrange_neg(CuTest *tc) {
+	char *line[] = {"(", "levelrange", "range", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_constrain(CuTest *tc) {
+	char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_constrain_neg(CuTest *tc) {
+	char *line[] = {"(", "constrain", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_mlsconstrain(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_mlsconstrain_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_context(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_context_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_filecon(CuTest *tc) {
+	char *line[] = {"(", "filecon", "root", "path", "file", "context", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_filecon_neg(CuTest *tc) {
+	char *line[] = {"(", "filecon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_portcon(CuTest *tc) {
+	char *line[] = {"(", "portcon", "udp", "25", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_portcon_neg(CuTest *tc) {
+	char *line[] = {"(", "portcon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_nodecon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_nodecon_neg(CuTest *tc) {
+	char *line[] = {"(", "nodecon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_genfscon(CuTest *tc) {
+	char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_genfscon_neg(CuTest *tc) {
+	char *line[] = {"(", "genfscon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_netifcon(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_netifcon_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pirqcon(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pirqcon_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_iomemcon(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_iomemcon_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ioportcon(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ioportcon_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_fsuse(CuTest *tc) {
+	char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_fsuse_neg(CuTest *tc) {
+	char *line[] = {"(", "fsuse", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_nested_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_macro *macro;
+	cil_macro_init(&macro);
+
+	struct cil_tree_node *macronode;
+	cil_tree_node_init(&macronode);
+	macronode->data = macro;
+	macronode->flavor = CIL_MACRO;
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, macronode, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+	cil_db_destroy(&test_db);
+	cil_destroy_macro(macro);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg(CuTest *tc) {
+	char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "allow", "foo", "bar", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_macro *macro;
+	cil_macro_init(&macro);
+	
+	struct cil_tree_node *macronode;
+	cil_tree_node_init(&macronode);
+	macronode->data = macro;
+	macronode->flavor = CIL_MACRO;
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, macronode, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+	cil_db_destroy(&test_db);
+	cil_destroy_macro(macro);
+}
+
+void test_cil_build_ast_node_helper_gen_call(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_call_neg(CuTest *tc) {
+	char *line[] = {"(", "call", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_optional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_optional_neg(CuTest *tc) {
+	char *line[] = {"(", "optional", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_policycap(CuTest *tc) {
+	char *line[] = {"(", "policycap", "open_perms", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 1);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_policycap_neg(CuTest *tc) {
+	char *line[] = {"(", "policycap", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ipaddr_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_extraargsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_args_build *extra_args = NULL;
+
+	uint32_t finished = 0;
+	
+	int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_last_child_helper(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+	
+	int rc = __cil_build_ast_last_child_helper(test_tree->root->cl_head->cl_head, extra_args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_last_child_helper_extraargsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	int rc = __cil_build_ast_last_child_helper(test_tree->root->cl_head->cl_head, NULL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_build_ast.h b/libsepol/cil/test/unit/test_cil_build_ast.h
new file mode 100644
index 0000000..d697433
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_build_ast.h
@@ -0,0 +1,1198 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_BUILD_AST_H_
+#define TEST_CIL_BUILD_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_parse_to_list(CuTest *);
+void test_cil_parse_to_list_currnull_neg(CuTest *);
+void test_cil_parse_to_list_listnull_neg(CuTest *);
+
+void test_cil_set_to_list(CuTest *);
+void test_cil_set_to_list_tree_node_null_neg(CuTest *);
+void test_cil_set_to_list_cl_head_null_neg(CuTest *);
+void test_cil_set_to_list_listnull_neg(CuTest *);
+
+void test_cil_gen_block(CuTest *);
+void test_cil_gen_block_justblock_neg(CuTest *);
+void test_cil_gen_block_noname_neg(CuTest *);
+void test_cil_gen_block_dbnull_neg(CuTest *);
+void test_cil_gen_block_treenull_neg(CuTest *);
+void test_cil_gen_block_nodenull_neg(CuTest *);
+void test_cil_gen_block_nodeparentnull_neg(CuTest *);
+void test_cil_destroy_block(CuTest *);
+
+void test_cil_gen_blockinherit(CuTest *);
+void test_cil_gen_blockinherit_namelist_neg(CuTest *);
+void test_cil_gen_blockinherit_namenull_neg(CuTest *);
+void test_cil_gen_blockinherit_extra_neg(CuTest *);
+void test_cil_gen_blockinherit_dbnull_neg(CuTest *);
+void test_cil_gen_blockinherit_currnull_neg(CuTest *);
+void test_cil_gen_blockinherit_astnull_neg(CuTest *);
+
+void test_cil_gen_perm(CuTest *);
+void test_cil_gen_perm_noname_neg(CuTest *);
+void test_cil_gen_perm_dbnull_neg(CuTest *);
+void test_cil_gen_perm_currnull_neg(CuTest *);
+void test_cil_gen_perm_astnull_neg(CuTest *);
+void test_cil_gen_perm_nodenull_neg(CuTest *);
+
+void test_cil_gen_permset(CuTest *);
+void test_cil_gen_permset_noname_neg(CuTest *);
+void test_cil_gen_permset_nameinparens_neg(CuTest *);
+void test_cil_gen_permset_noperms_neg(CuTest *);
+void test_cil_gen_permset_emptyperms_neg(CuTest *);
+void test_cil_gen_permset_extra_neg(CuTest *);
+void test_cil_gen_permset_dbnull_neg(CuTest *);
+void test_cil_gen_permset_currnull_neg(CuTest *);
+void test_cil_gen_permset_astnull_neg(CuTest *);
+
+void test_cil_gen_perm_nodes(CuTest *);
+void test_cil_gen_perm_nodes_failgen_neg(CuTest *);
+void test_cil_gen_perm_nodes_inval_perm_neg(CuTest *);
+
+void test_cil_fill_permset(CuTest *);
+void test_cil_fill_permset_sublist_neg(CuTest *);
+void test_cil_fill_permset_startpermnull_neg(CuTest *);
+void test_cil_fill_permset_permsetnull_neg(CuTest *);
+
+void test_cil_gen_in(CuTest *);
+void test_cil_gen_in_blockstrnull_neg(CuTest *);
+void test_cil_gen_in_extra_neg(CuTest *);
+void test_cil_gen_in_dbnull_neg(CuTest *);
+void test_cil_gen_in_currnull_neg(CuTest *);
+void test_cil_gen_in_astnull_neg(CuTest *);
+
+void test_cil_gen_class(CuTest *);
+void test_cil_gen_class_noname_neg(CuTest *);
+void test_cil_gen_class_nodenull_neg(CuTest *);
+void test_cil_gen_class_dbnull_neg(CuTest *);
+void test_cil_gen_class_currnull_neg(CuTest *);
+void test_cil_gen_class_noclass_neg(CuTest *);
+void test_cil_gen_class_noclassname_neg(CuTest *);
+void test_cil_gen_class_namesublist_neg(CuTest *);
+void test_cil_gen_class_noperms(CuTest *);
+void test_cil_gen_class_permsnotinlist_neg(CuTest *);
+void test_cil_gen_class_extrapermlist_neg(CuTest *);
+void test_cil_gen_class_listinlist_neg(CuTest *);
+
+void test_cil_fill_classpermset_anonperms(CuTest *);
+void test_cil_fill_classpermset_anonperms_neg(CuTest *);
+void test_cil_fill_classpermset_namedperms(CuTest *);
+void test_cil_fill_classpermset_extra_neg(CuTest *);
+void test_cil_fill_classpermset_emptypermslist_neg(CuTest *);
+void test_cil_fill_classpermset_noperms_neg(CuTest *);
+void test_cil_fill_classpermset_noclass_neg(CuTest *);
+void test_cil_fill_classpermset_classnodenull_neg(CuTest *);
+void test_cil_fill_classpermset_cpsnull_neg(CuTest *);
+
+void test_cil_gen_classpermset(CuTest *);
+void test_cil_gen_classpermset_noname_neg(CuTest *);
+void test_cil_gen_classpermset_nameinparens_neg(CuTest *);
+void test_cil_gen_classpermset_noclass_neg(CuTest *);
+void test_cil_gen_classpermset_noperms_neg(CuTest *);
+void test_cil_gen_classpermset_emptyperms_neg(CuTest *);
+void test_cil_gen_classpermset_extra_neg(CuTest *);
+void test_cil_gen_classpermset_dbnull_neg(CuTest *);
+void test_cil_gen_classpermset_currnull_neg(CuTest *);
+void test_cil_gen_classpermset_astnull_neg(CuTest *);
+
+void test_cil_gen_classmap_perm(CuTest *);
+void test_cil_gen_classmap_perm_dupeperm_neg(CuTest *);
+void test_cil_gen_classmap_perm_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmap_perm_currnull_neg(CuTest *tc);
+void test_cil_gen_classmap_perm_astnull_neg(CuTest *tc);
+
+void test_cil_gen_classmap(CuTest *);
+void test_cil_gen_classmap_extra_neg(CuTest *);
+void test_cil_gen_classmap_noname_neg(CuTest *);
+void test_cil_gen_classmap_emptyperms_neg(CuTest *);
+void test_cil_gen_classmap_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmap_currnull_neg(CuTest *tc);
+void test_cil_gen_classmap_astnull_neg(CuTest *tc);
+
+void test_cil_gen_classmapping_anonpermset(CuTest *);
+void test_cil_gen_classmapping_anonpermset_neg(CuTest *);
+void test_cil_gen_classmapping_namedpermset(CuTest *);
+void test_cil_gen_classmapping_noclassmapname_neg(CuTest *);
+void test_cil_gen_classmapping_noclassmapperm_neg(CuTest *);
+void test_cil_gen_classmapping_nopermissionsets_neg(CuTest *);
+void test_cil_gen_classmapping_emptyperms_neg(CuTest *);
+void test_cil_gen_classmapping_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmapping_currnull_neg(CuTest *tc);
+void test_cil_gen_classmapping_astnull_neg(CuTest *tc);
+
+void test_cil_gen_common(CuTest *);
+void test_cil_gen_common_dbnull_neg(CuTest *tc);
+void test_cil_gen_common_currnull_neg(CuTest *tc);
+void test_cil_gen_common_astnull_neg(CuTest *tc);
+void test_cil_gen_common_noname_neg(CuTest *tc);
+void test_cil_gen_common_twoperms_neg(CuTest *tc);
+void test_cil_gen_common_permsublist_neg(CuTest *tc);
+void test_cil_gen_common_noperms_neg(CuTest *tc);
+
+void test_cil_gen_sid(CuTest *);
+void test_cil_gen_sid_noname_neg(CuTest *);
+void test_cil_gen_sid_nameinparens_neg(CuTest *);
+void test_cil_gen_sid_extra_neg(CuTest *);
+void test_cil_gen_sid_dbnull_neg(CuTest *);
+void test_cil_gen_sid_currnull_neg(CuTest *);
+void test_cil_gen_sid_astnull_neg(CuTest *);
+
+void test_cil_gen_sidcontext(CuTest *);
+void test_cil_gen_sidcontext_namedcontext(CuTest *);
+void test_cil_gen_sidcontext_halfcontext_neg(CuTest *);
+void test_cil_gen_sidcontext_noname_neg(CuTest *);
+void test_cil_gen_sidcontext_empty_neg(CuTest *);
+void test_cil_gen_sidcontext_nocontext_neg(CuTest *);
+void test_cil_gen_sidcontext_dblname_neg(CuTest *);
+void test_cil_gen_sidcontext_dbnull_neg(CuTest *);
+void test_cil_gen_sidcontext_pcurrnull_neg(CuTest *);
+void test_cil_gen_sidcontext_astnodenull_neg(CuTest *);
+
+void test_cil_gen_type(CuTest *);
+void test_cil_gen_type_neg(CuTest *);
+void test_cil_gen_type_dbnull_neg(CuTest *tc);
+void test_cil_gen_type_currnull_neg(CuTest *tc);
+void test_cil_gen_type_astnull_neg(CuTest *tc);
+void test_cil_gen_type_extra_neg(CuTest *tc);
+
+void test_cil_gen_typeattribute(CuTest *);
+void test_cil_gen_typeattribute_dbnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_currnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_astnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_extra_neg(CuTest *tc);
+
+void test_cil_gen_typeattr(CuTest *);
+void test_cil_gen_typeattr_dbnull_neg(CuTest *);
+void test_cil_gen_typeattr_currnull_neg(CuTest *);
+void test_cil_gen_typeattr_astnull_neg(CuTest *);
+void test_cil_gen_typeattr_typenull_neg(CuTest *);
+void test_cil_gen_typeattr_attrnull_neg(CuTest *);
+void test_cil_gen_typeattr_attrlist_neg(CuTest *);
+void test_cil_gen_typeattr_extra_neg(CuTest *);
+
+void test_cil_gen_typebounds(CuTest *);
+void test_cil_gen_typebounds_notype1_neg(CuTest *);
+void test_cil_gen_typebounds_type1inparens_neg(CuTest *);
+void test_cil_gen_typebounds_notype2_neg(CuTest *);
+void test_cil_gen_typebounds_type2inparens_neg(CuTest *);
+void test_cil_gen_typebounds_extra_neg(CuTest *);
+void test_cil_gen_typebounds_dbnull_neg(CuTest *);
+void test_cil_gen_typebounds_currnull_neg(CuTest *);
+void test_cil_gen_typebounds_astnull_neg(CuTest *);
+
+void test_cil_gen_typepermissive(CuTest *);
+void test_cil_gen_typepermissive_noname_neg(CuTest *);
+void test_cil_gen_typepermissive_typeinparens_neg(CuTest *);
+void test_cil_gen_typepermissive_extra_neg(CuTest *);
+void test_cil_gen_typepermissive_dbnull_neg(CuTest *);
+void test_cil_gen_typepermissive_currnull_neg(CuTest *);
+void test_cil_gen_typepermissive_astnull_neg(CuTest *);
+
+void test_cil_gen_nametypetransition(CuTest *);
+void test_cil_gen_nametypetransition_nostr_neg(CuTest *);
+void test_cil_gen_nametypetransition_strinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_nosrc_neg(CuTest *);
+void test_cil_gen_nametypetransition_srcinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_notgt_neg(CuTest *);
+void test_cil_gen_nametypetransition_tgtinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_noclass_neg(CuTest *);
+void test_cil_gen_nametypetransition_classinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_nodest_neg(CuTest *);
+void test_cil_gen_nametypetransition_destinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_extra_neg(CuTest *);
+void test_cil_gen_nametypetransition_dbnull_neg(CuTest *);
+void test_cil_gen_nametypetransition_currnull_neg(CuTest *);
+void test_cil_gen_nametypetransition_astnull_neg(CuTest *);
+
+void test_cil_gen_rangetransition(CuTest *);
+void test_cil_gen_rangetransition_namedtransition(CuTest *);
+void test_cil_gen_rangetransition_anon_low_l(CuTest *);
+void test_cil_gen_rangetransition_anon_low_l_neg(CuTest *);
+void test_cil_gen_rangetransition_anon_high_l(CuTest *);
+void test_cil_gen_rangetransition_anon_high_l_neg(CuTest *);
+void test_cil_gen_rangetransition_dbnull_neg(CuTest *);
+void test_cil_gen_rangetransition_currnull_neg(CuTest *);
+void test_cil_gen_rangetransition_astnull_neg(CuTest *);
+void test_cil_gen_rangetransition_nofirsttype_neg(CuTest *);
+void test_cil_gen_rangetransition_firsttype_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_nosecondtype_neg(CuTest *);
+void test_cil_gen_rangetransition_secondtype_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_noclass_neg(CuTest *);
+void test_cil_gen_rangetransition_class_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_nolevel_l_neg(CuTest *);
+void test_cil_gen_rangetransition_nolevel_h_neg(CuTest *);
+void test_cil_gen_rangetransition_extra_neg(CuTest *);
+
+void test_cil_gen_expr_stack_and(CuTest *);
+void test_cil_gen_expr_stack_or(CuTest *);
+void test_cil_gen_expr_stack_xor(CuTest *);
+void test_cil_gen_expr_stack_not(CuTest *);
+void test_cil_gen_expr_stack_not_noexpr_neg(CuTest *);
+void test_cil_gen_expr_stack_not_extraexpr_neg(CuTest *);
+void test_cil_gen_expr_stack_eq(CuTest *);
+void test_cil_gen_expr_stack_neq(CuTest *);
+void test_cil_gen_expr_stack_nested(CuTest *);
+void test_cil_gen_expr_stack_nested_neg(CuTest *);
+void test_cil_gen_expr_stack_nested_emptyargs_neg(CuTest *);
+void test_cil_gen_expr_stack_nested_missingoperator_neg(CuTest *);
+void test_cil_gen_expr_stack_arg1null_neg(CuTest *);
+void test_cil_gen_expr_stack_arg2null_neg(CuTest *);
+void test_cil_gen_expr_stack_extraarg_neg(CuTest *);
+void test_cil_gen_expr_stack_currnull_neg(CuTest *);
+void test_cil_gen_expr_stack_stacknull_neg(CuTest *);
+
+void test_cil_gen_boolif_multiplebools_true(CuTest *);
+void test_cil_gen_boolif_multiplebools_false(CuTest *);
+void test_cil_gen_boolif_multiplebools_unknowncond_neg(CuTest *);
+void test_cil_gen_boolif_true(CuTest *);
+void test_cil_gen_boolif_false(CuTest *);
+void test_cil_gen_boolif_unknowncond_neg(CuTest *);
+void test_cil_gen_boolif_nested(CuTest *);
+void test_cil_gen_boolif_nested_neg(CuTest *);
+void test_cil_gen_boolif_extra_neg(CuTest *);
+void test_cil_gen_boolif_extra_parens_neg(CuTest *);
+void test_cil_gen_boolif_nocond(CuTest *);
+void test_cil_gen_boolif_neg(CuTest *);
+void test_cil_gen_boolif_dbnull_neg(CuTest *);
+void test_cil_gen_boolif_currnull_neg(CuTest *);
+void test_cil_gen_boolif_astnull_neg(CuTest *);
+void test_cil_gen_boolif_nocond_neg(CuTest *);
+void test_cil_gen_boolif_notruelist_neg(CuTest *);
+void test_cil_gen_boolif_empty_cond_neg(CuTest *);
+
+void test_cil_gen_else(CuTest *);
+void test_cil_gen_else_neg(CuTest *);
+void test_cil_gen_else_dbnull_neg(CuTest *);
+void test_cil_gen_else_currnull_neg(CuTest *);
+void test_cil_gen_else_astnull_neg(CuTest *);
+
+void test_cil_gen_tunif_multiplebools_true(CuTest *);
+void test_cil_gen_tunif_multiplebools_false(CuTest *);
+void test_cil_gen_tunif_multiplebools_unknowncond_neg(CuTest *);
+void test_cil_gen_tunif_true(CuTest *);
+void test_cil_gen_tunif_false(CuTest *);
+void test_cil_gen_tunif_unknowncond_neg(CuTest *);
+void test_cil_gen_tunif_nocond(CuTest *);
+void test_cil_gen_tunif_nested(CuTest *);
+void test_cil_gen_tunif_nested_neg(CuTest *);
+void test_cil_gen_tunif_extra_neg(CuTest *);
+void test_cil_gen_tunif_extra_parens_neg(CuTest *);
+void test_cil_gen_tunif_neg(CuTest *);
+void test_cil_gen_tunif_dbnull_neg(CuTest *);
+void test_cil_gen_tunif_currnull_neg(CuTest *);
+void test_cil_gen_tunif_astnull_neg(CuTest *);
+void test_cil_gen_tunif_nocond_neg(CuTest *);
+void test_cil_gen_tunif_notruelist_neg(CuTest *);
+
+void test_cil_gen_condblock_true(CuTest *);
+void test_cil_gen_condblock_false(CuTest *);
+void test_cil_gen_condblock_dbnull_neg(CuTest *);
+void test_cil_gen_condblock_currnull_neg(CuTest *);
+void test_cil_gen_condblock_astnull_neg(CuTest *);
+void test_cil_gen_condblock_nocond_neg(CuTest *);
+void test_cil_gen_condblock_extra_neg(CuTest *);
+
+void test_cil_gen_typealias(CuTest *);
+void test_cil_gen_typealias_incomplete_neg(CuTest *);
+void test_cil_gen_typealias_incomplete_neg2(CuTest *);
+void test_cil_gen_typealias_extratype_neg(CuTest *);
+void test_cil_gen_typealias_dbnull_neg(CuTest *tc);
+void test_cil_gen_typealias_currnull_neg(CuTest *tc);
+void test_cil_gen_typealias_astnull_neg(CuTest *tc);
+
+void test_cil_gen_typeattributeset(CuTest *);
+void test_cil_gen_typeattributeset_and_two_types(CuTest *);
+void test_cil_gen_typeattributeset_not(CuTest *);
+void test_cil_gen_typeattributeset_exclude_attr(CuTest *);
+void test_cil_gen_typeattributeset_exclude_neg(CuTest *);
+void test_cil_gen_typeattributeset_dbnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_currnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_astnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_noname_neg(CuTest *);
+void test_cil_gen_typeattributeset_nameinparens_neg(CuTest *);
+void test_cil_gen_typeattributeset_emptylists_neg(CuTest *);
+void test_cil_gen_typeattributeset_listinparens_neg(CuTest *);
+void test_cil_gen_typeattributeset_extra_neg(CuTest *);
+
+void test_cil_gen_userbounds(CuTest *);
+void test_cil_gen_userbounds_notype1_neg(CuTest *);
+void test_cil_gen_userbounds_type1_inparens_neg(CuTest *);
+void test_cil_gen_userbounds_notype2_neg(CuTest *);
+void test_cil_gen_userbounds_type2_inparens_neg(CuTest *);
+void test_cil_gen_userbounds_extra_neg(CuTest *);
+void test_cil_gen_userbounds_dbnull_neg(CuTest *);
+void test_cil_gen_userbounds_currnull_neg(CuTest *);
+void test_cil_gen_userbounds_astnull_neg(CuTest *);
+
+void test_cil_gen_role(CuTest *);
+void test_cil_gen_role_dbnull_neg(CuTest *tc);
+void test_cil_gen_role_currnull_neg(CuTest *tc);
+void test_cil_gen_role_astnull_neg(CuTest *tc);
+void test_cil_gen_role_extrarole_neg(CuTest *tc);
+void test_cil_gen_role_noname_neg(CuTest *tc);
+
+void test_cil_gen_roletransition(CuTest *);
+void test_cil_gen_roletransition_currnull_neg(CuTest *);
+void test_cil_gen_roletransition_astnull_neg(CuTest *);
+void test_cil_gen_roletransition_srcnull_neg(CuTest *);
+void test_cil_gen_roletransition_tgtnull_neg(CuTest *);
+void test_cil_gen_roletransition_resultnull_neg(CuTest *);
+void test_cil_gen_roletransition_extra_neg(CuTest *);
+
+void test_cil_gen_bool_true(CuTest *);
+void test_cil_gen_bool_tunable_true(CuTest *);
+void test_cil_gen_bool_false(CuTest *);
+void test_cil_gen_bool_tunable_false(CuTest *);
+void test_cil_gen_bool_none_neg(CuTest *);
+void test_cil_gen_bool_dbnull_neg(CuTest *);
+void test_cil_gen_bool_currnull_neg(CuTest *);
+void test_cil_gen_bool_astnull_neg(CuTest *);
+void test_cil_gen_bool_notbool_neg(CuTest *);
+void test_cil_gen_bool_boolname_neg(CuTest *);
+void test_cil_gen_bool_extraname_false_neg(CuTest *);
+void test_cil_gen_bool_extraname_true_neg(CuTest *);
+
+void test_cil_gen_constrain_expr_stack_eq2_t1type(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t1t1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t2type(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t2t2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1role(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1r1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r2role(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r2r2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t1t2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_r1r2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1r2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1u2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1user(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1u1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u2user(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u2u2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l2h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1h1(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1l2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_emptyparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_extraparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_currnull_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_stacknull_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_operatorinparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incorrectcall_neg(CuTest *);
+
+void test_cil_gen_roleallow(CuTest *);
+void test_cil_gen_roleallow_dbnull_neg(CuTest *);
+void test_cil_gen_roleallow_currnull_neg(CuTest *);
+void test_cil_gen_roleallow_astnull_neg(CuTest *);
+void test_cil_gen_roleallow_srcnull_neg(CuTest *);
+void test_cil_gen_roleallow_tgtnull_neg(CuTest *);
+void test_cil_gen_roleallow_extra_neg(CuTest *);
+
+void test_cil_gen_rolebounds(CuTest *);
+void test_cil_gen_rolebounds_norole1_neg(CuTest *);
+void test_cil_gen_rolebounds_role1_inparens_neg(CuTest *);
+void test_cil_gen_rolebounds_norole2_neg(CuTest *);
+void test_cil_gen_rolebounds_role2_inparens_neg(CuTest *);
+void test_cil_gen_rolebounds_extra_neg(CuTest *);
+void test_cil_gen_rolebounds_dbnull_neg(CuTest *);
+void test_cil_gen_rolebounds_currnull_neg(CuTest *);
+void test_cil_gen_rolebounds_astnull_neg(CuTest *);
+
+void test_cil_gen_avrule(CuTest *);
+void test_cil_gen_avrule_permset(CuTest *);
+void test_cil_gen_avrule_permset_anon(CuTest *);
+void test_cil_gen_avrule_extra_neg(CuTest *);
+void test_cil_gen_avrule_sourceparens(CuTest *);
+void test_cil_gen_avrule_sourceemptyparen_neg(CuTest *);
+void test_cil_gen_avrule_targetparens(CuTest *);
+void test_cil_gen_avrule_targetemptyparen_neg(CuTest *);
+void test_cil_gen_avrule_currnull_neg(CuTest *tc);
+void test_cil_gen_avrule_astnull_neg(CuTest *tc);
+void test_cil_gen_avrule_sourcedomainnull_neg(CuTest *tc);
+void test_cil_gen_avrule_targetdomainnull_neg(CuTest *tc);
+void test_cil_gen_avrule_objectclassnull_neg(CuTest *tc);
+void test_cil_gen_avrule_permsnull_neg(CuTest *tc);
+void test_cil_gen_avrule_twolists_neg(CuTest *);
+//TODO: add cases to cover  parse_current->next->cl_head != NULL || parse_current->next->next->cl_head != NULL 
+// || parse_current->next->next->next->cl_head != NULL
+
+void test_cil_gen_type_rule_transition(CuTest *);
+void test_cil_gen_type_rule_transition_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_extra_neg(CuTest *);
+
+void test_cil_gen_type_rule_change(CuTest *);
+void test_cil_gen_type_rule_change_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_extra_neg(CuTest *);
+
+void test_cil_gen_type_rule_member(CuTest *); 
+void test_cil_gen_type_rule_member_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_extra_neg(CuTest *);
+
+void test_cil_gen_user(CuTest *);
+void test_cil_gen_user_dbnull_neg(CuTest *);
+void test_cil_gen_user_currnull_neg(CuTest *);
+void test_cil_gen_user_astnull_neg(CuTest *);
+void test_cil_gen_user_nouser_neg(CuTest *);
+void test_cil_gen_user_xsinfo_neg(CuTest *);
+
+void test_cil_gen_userlevel(CuTest *);
+void test_cil_gen_userlevel_anon_level(CuTest *);
+void test_cil_gen_userlevel_anon_level_neg(CuTest *);
+void test_cil_gen_userlevel_usernull_neg(CuTest *);
+void test_cil_gen_userlevel_userrange_neg(CuTest *);
+void test_cil_gen_userlevel_levelnull_neg(CuTest *);
+void test_cil_gen_userlevel_levelrangeempty_neg(CuTest *);
+void test_cil_gen_userlevel_extra_neg(CuTest *);
+void test_cil_gen_userlevel_dbnull_neg(CuTest *);
+void test_cil_gen_userlevel_currnull_neg(CuTest *);
+void test_cil_gen_userlevel_astnull_neg(CuTest *);
+
+void test_cil_gen_userrange_named(CuTest *);
+void test_cil_gen_userrange_anon(CuTest *);
+void test_cil_gen_userrange_usernull_neg(CuTest *);
+void test_cil_gen_userrange_anonuser_neg(CuTest *);
+void test_cil_gen_userrange_rangenamenull_neg(CuTest *);
+void test_cil_gen_userrange_anonrangeinvalid_neg(CuTest *);
+void test_cil_gen_userrange_anonrangeempty_neg(CuTest *);
+void test_cil_gen_userrange_extra_neg(CuTest *);
+void test_cil_gen_userrange_dbnull_neg(CuTest *);
+void test_cil_gen_userrange_currnull_neg(CuTest *);
+void test_cil_gen_userrange_astnull_neg(CuTest *);
+
+void test_cil_gen_sensitivity(CuTest *);
+void test_cil_gen_sensitivity_dbnull_neg(CuTest *);
+void test_cil_gen_sensitivity_currnull_neg(CuTest *);
+void test_cil_gen_sensitivity_astnull_neg(CuTest *);
+void test_cil_gen_sensitivity_sensnull_neg(CuTest *);
+void test_cil_gen_sensitivity_senslist_neg(CuTest *);
+void test_cil_gen_sensitivity_extra_neg(CuTest *);
+
+void test_cil_gen_sensalias(CuTest *);
+void test_cil_gen_sensalias_dbnull_neg(CuTest *);
+void test_cil_gen_sensalias_currnull_neg(CuTest *);
+void test_cil_gen_sensalias_astnull_neg(CuTest *);
+void test_cil_gen_sensalias_sensnull_neg(CuTest *);
+void test_cil_gen_sensalias_senslist_neg(CuTest *);
+void test_cil_gen_sensalias_aliasnull_neg(CuTest *);
+void test_cil_gen_sensalias_aliaslist_neg(CuTest *);
+void test_cil_gen_sensalias_extra_neg(CuTest *);
+
+void test_cil_gen_category(CuTest *);
+void test_cil_gen_category_dbnull_neg(CuTest *); 
+void test_cil_gen_category_astnull_neg(CuTest *);
+void test_cil_gen_category_currnull_neg(CuTest *);
+void test_cil_gen_category_catnull_neg(CuTest *);
+void test_cil_gen_category_catlist_neg(CuTest *);
+void test_cil_gen_category_extra_neg(CuTest *);
+
+void test_cil_gen_catset(CuTest *);
+void test_cil_gen_catset_dbnull_neg(CuTest *);
+void test_cil_gen_catset_currnull_neg(CuTest *);
+void test_cil_gen_catset_astnull_neg(CuTest *);
+void test_cil_gen_catset_namenull_neg(CuTest *);
+void test_cil_gen_catset_setnull_neg(CuTest *);
+void test_cil_gen_catset_namelist_neg(CuTest *);
+void test_cil_gen_catset_extra_neg(CuTest *);
+void test_cil_gen_catset_nodefail_neg(CuTest *);
+void test_cil_gen_catset_notset_neg(CuTest *);
+void test_cil_gen_catset_settolistfail_neg(CuTest *);
+
+void test_cil_gen_catalias(CuTest *);
+void test_cil_gen_catalias_dbnull_neg(CuTest *);
+void test_cil_gen_catalias_currnull_neg(CuTest *);
+void test_cil_gen_catalias_astnull_neg(CuTest *);
+void test_cil_gen_catalias_catnull_neg(CuTest *);
+void test_cil_gen_catalias_aliasnull_neg(CuTest *);
+void test_cil_gen_catalias_extra_neg(CuTest *);
+
+void test_cil_gen_catrange(CuTest *);
+void test_cil_gen_catrange_noname_neg(CuTest *);
+void test_cil_gen_catrange_norange_neg(CuTest *);
+void test_cil_gen_catrange_emptyrange_neg(CuTest *);
+void test_cil_gen_catrange_extrarange_neg(CuTest *);
+void test_cil_gen_catrange_dbnull_neg(CuTest *);
+void test_cil_gen_catrange_currnull_neg(CuTest *);
+void test_cil_gen_catrange_astnull_neg(CuTest *);
+void test_cil_gen_catrange_extra_neg(CuTest *);
+
+void test_cil_gen_roletype(CuTest *tc);
+void test_cil_gen_roletype_currnull_neg(CuTest *tc);
+void test_cil_gen_roletype_dbnull_neg(CuTest *tc);
+void test_cil_gen_roletype_astnull_neg(CuTest *tc);
+void test_cil_gen_roletype_empty_neg(CuTest *tc);
+void test_cil_gen_roletype_rolelist_neg(CuTest *tc);
+void test_cil_gen_roletype_roletype_sublist_neg(CuTest *tc);
+void test_cil_gen_roletype_typelist_neg(CuTest *tc);
+
+void test_cil_gen_userrole(CuTest *tc);
+void test_cil_gen_userrole_currnull_neg(CuTest *tc);
+void test_cil_gen_userrole_dbnull_neg(CuTest *tc);
+void test_cil_gen_userrole_astnull_neg(CuTest *tc);
+void test_cil_gen_userrole_empty_neg(CuTest *tc);
+void test_cil_gen_userrole_userlist_neg(CuTest *tc);
+void test_cil_gen_userrole_userrole_sublist_neg(CuTest *tc);
+void test_cil_gen_userrole_rolelist_neg(CuTest *tc);
+
+void test_cil_gen_classcommon(CuTest *tc);
+void test_cil_gen_classcommon_dbnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_currnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_astnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_missingclassname_neg(CuTest *tc);
+void test_cil_gen_classcommon_noperms_neg(CuTest *tc);
+void test_cil_gen_classcommon_extraperms_neg(CuTest *tc);
+
+void test_cil_gen_catorder(CuTest *tc);
+void test_cil_gen_catorder_dbnull_neg(CuTest *tc);
+void test_cil_gen_catorder_currnull_neg(CuTest *tc);
+void test_cil_gen_catorder_astnull_neg(CuTest *tc);
+void test_cil_gen_catorder_missingcats_neg(CuTest *tc);
+void test_cil_gen_catorder_nosublist_neg(CuTest *tc);
+void test_cil_gen_catorder_nestedcat_neg(CuTest *tc);
+
+void test_cil_gen_dominance(CuTest *tc);
+void test_cil_gen_dominance_dbnull_neg(CuTest *tc);
+void test_cil_gen_dominance_currnull_neg(CuTest *tc);
+void test_cil_gen_dominance_astnull_neg(CuTest *tc);
+void test_cil_gen_dominance_nosensitivities_neg(CuTest *tc);
+void test_cil_gen_dominance_nosublist_neg(CuTest *tc);
+
+void test_cil_gen_senscat(CuTest *tc);
+void test_cil_gen_senscat_nosublist(CuTest *);
+void test_cil_gen_senscat_dbnull_neg(CuTest *tc);
+void test_cil_gen_senscat_currnull_neg(CuTest *tc);
+void test_cil_gen_senscat_astnull_neg(CuTest *tc);
+void test_cil_gen_senscat_nosensitivities_neg(CuTest *tc);
+void test_cil_gen_senscat_sublist_neg(CuTest *);
+void test_cil_gen_senscat_nocat_neg(CuTest *);
+
+void test_cil_fill_level(CuTest *tc);
+void test_cil_fill_level_sensnull_neg(CuTest *tc);
+void test_cil_fill_level_levelnull_neg(CuTest *tc);
+void test_cil_fill_level_nocat(CuTest *tc);
+void test_cil_fill_level_emptycat_neg(CuTest *tc);
+
+void test_cil_gen_level(CuTest *tc);
+void test_cil_gen_level_nameinparens_neg(CuTest *tc);
+void test_cil_gen_level_emptysensparens_neg(CuTest *tc);
+void test_cil_gen_level_extra_neg(CuTest *tc);
+void test_cil_gen_level_emptycat_neg(CuTest *tc);
+void test_cil_gen_level_noname_neg(CuTest *tc);
+void test_cil_gen_level_nosens_neg(CuTest *tc);
+void test_cil_gen_level_dbnull_neg(CuTest *tc);
+void test_cil_gen_level_currnull_neg(CuTest *tc);
+void test_cil_gen_level_astnull_neg(CuTest *tc);
+
+void test_cil_gen_levelrange(CuTest *tc);
+void test_cil_gen_levelrange_rangeinvalid_neg(CuTest *tc);
+void test_cil_gen_levelrange_namenull_neg(CuTest *tc);
+void test_cil_gen_levelrange_rangenull_neg(CuTest *tc);
+void test_cil_gen_levelrange_rangeempty_neg(CuTest *tc);
+void test_cil_gen_levelrange_extra_neg(CuTest *tc);
+void test_cil_gen_levelrange_dbnull_neg(CuTest *tc);
+void test_cil_gen_levelrange_currnull_neg(CuTest *tc);
+void test_cil_gen_levelrange_astnull_neg(CuTest *tc);
+
+void test_cil_gen_constrain(CuTest *tc);
+void test_cil_gen_constrain_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_noclass_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_noperm_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_noclass_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_noperm_neg(CuTest *tc);
+void test_cil_gen_constrain_expression_neg(CuTest *tc);
+void test_cil_gen_constrain_dbnull_neg(CuTest *tc);
+void test_cil_gen_constrain_currnull_neg(CuTest *tc);
+void test_cil_gen_constrain_astnull_neg(CuTest *tc);
+
+void test_cil_fill_context(CuTest *tc);
+void test_cil_fill_context_unnamedlvl(CuTest *tc);
+void test_cil_fill_context_nocontext_neg(CuTest *tc);
+void test_cil_fill_context_nouser_neg(CuTest *tc);
+void test_cil_fill_context_norole_neg(CuTest *tc);
+void test_cil_fill_context_notype_neg(CuTest *tc);
+void test_cil_fill_context_nolowlvl_neg(CuTest *tc);
+void test_cil_fill_context_nohighlvl_neg(CuTest *tc);
+void test_cil_fill_context_unnamedlvl_nocontextlow_neg(CuTest *tc);
+void test_cil_fill_context_unnamedlvl_nocontexthigh_neg(CuTest *tc);
+
+void test_cil_gen_context(CuTest *tc);
+void test_cil_gen_context_notinparens_neg(CuTest *tc);
+void test_cil_gen_context_extralevel_neg(CuTest *tc);
+void test_cil_gen_context_emptycontext_neg(CuTest *tc);
+void test_cil_gen_context_extra_neg(CuTest *tc);
+void test_cil_gen_context_doubleparen_neg(CuTest *tc);
+void test_cil_gen_context_norole_neg(CuTest *tc);
+void test_cil_gen_context_roleinparens_neg(CuTest *tc);
+void test_cil_gen_context_notype_neg(CuTest *tc);
+void test_cil_gen_context_typeinparens_neg(CuTest *tc);
+void test_cil_gen_context_nolevels_neg(CuTest *tc);
+void test_cil_gen_context_nosecondlevel_neg(CuTest *tc);
+void test_cil_gen_context_noname_neg(CuTest *tc);
+void test_cil_gen_context_nouser_neg(CuTest *tc);
+void test_cil_gen_context_dbnull_neg(CuTest *tc);
+void test_cil_gen_context_currnull_neg(CuTest *tc);
+void test_cil_gen_context_astnull_neg(CuTest *tc);
+
+void test_cil_gen_filecon_file(CuTest *tc);
+void test_cil_gen_filecon_dir(CuTest *tc);
+void test_cil_gen_filecon_char(CuTest *tc);
+void test_cil_gen_filecon_block(CuTest *tc);
+void test_cil_gen_filecon_socket(CuTest *tc);
+void test_cil_gen_filecon_pipe(CuTest *tc);
+void test_cil_gen_filecon_symlink(CuTest *tc);
+void test_cil_gen_filecon_any(CuTest *tc);
+void test_cil_gen_filecon_neg(CuTest *tc);
+void test_cil_gen_filecon_anon_context(CuTest *tc);
+void test_cil_gen_filecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_filecon_currnull_neg(CuTest *tc);
+void test_cil_gen_filecon_astnull_neg(CuTest *tc);
+void test_cil_gen_filecon_str1null_neg(CuTest *tc);
+void test_cil_gen_filecon_str1_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_str2null_neg(CuTest *tc);
+void test_cil_gen_filecon_str2_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_classnull_neg(CuTest *tc);
+void test_cil_gen_filecon_class_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_contextnull_neg(CuTest *tc);
+void test_cil_gen_filecon_context_neg(CuTest *tc);
+void test_cil_gen_filecon_extra_neg(CuTest *tc);
+
+void test_cil_gen_portcon_udp(CuTest *tc);
+void test_cil_gen_portcon_tcp(CuTest *tc);
+void test_cil_gen_portcon_unknownprotocol_neg(CuTest *tc);
+void test_cil_gen_portcon_anon_context(CuTest *tc);
+void test_cil_gen_portcon_portrange(CuTest *tc);
+void test_cil_gen_portcon_portrange_one_neg(CuTest *tc);
+void test_cil_gen_portcon_portrange_morethanone_neg(CuTest *tc);
+void test_cil_gen_portcon_singleport_neg(CuTest *tc);
+void test_cil_gen_portcon_lowport_neg(CuTest *tc);
+void test_cil_gen_portcon_highport_neg(CuTest *tc);
+void test_cil_gen_portcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_portcon_currnull_neg(CuTest *tc);
+void test_cil_gen_portcon_astnull_neg(CuTest *tc);
+void test_cil_gen_portcon_str1null_neg(CuTest *tc);
+void test_cil_gen_portcon_str1parens_neg(CuTest *tc);
+void test_cil_gen_portcon_portnull_neg(CuTest *tc);
+void test_cil_gen_portcon_contextnull_neg(CuTest *tc);
+void test_cil_gen_portcon_context_neg(CuTest *tc);
+void test_cil_gen_portcon_extra_neg(CuTest *tc);
+
+void test_cil_fill_ipaddr(CuTest *tc);
+void test_cil_fill_ipaddr_addrnodenull_neg(CuTest *tc);
+void test_cil_fill_ipaddr_addrnull_neg(CuTest *tc);
+void test_cil_fill_ipaddr_addrinparens_neg(CuTest *tc);
+void test_cil_fill_ipaddr_extra_neg(CuTest *tc);
+
+void test_cil_gen_nodecon(CuTest *tc);
+void test_cil_gen_nodecon_anon_context(CuTest *tc);
+void test_cil_gen_nodecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_currnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_astnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_ipnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_ipanon(CuTest *tc);
+void test_cil_gen_nodecon_ipanon_neg(CuTest *tc);
+void test_cil_gen_nodecon_netmasknull_neg(CuTest *tc);
+void test_cil_gen_nodecon_netmaskanon(CuTest *tc);
+void test_cil_gen_nodecon_netmaskanon_neg(CuTest *tc);
+void test_cil_gen_nodecon_contextnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_context_neg(CuTest *tc);
+void test_cil_gen_nodecon_extra_neg(CuTest *tc);
+
+void test_cil_gen_genfscon(CuTest *tc);
+void test_cil_gen_genfscon_anon_context(CuTest *tc);
+void test_cil_gen_genfscon_dbnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_currnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_astnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_typenull_neg(CuTest *tc);
+void test_cil_gen_genfscon_typeparens_neg(CuTest *tc);
+void test_cil_gen_genfscon_pathnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_pathparens_neg(CuTest *tc);
+void test_cil_gen_genfscon_contextnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_context_neg(CuTest *tc);
+void test_cil_gen_genfscon_extra_neg(CuTest *tc);
+
+void test_cil_gen_netifcon(CuTest *tc);
+void test_cil_gen_netifcon_nested(CuTest *tc);
+void test_cil_gen_netifcon_nested_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_emptysecondlist_neg(CuTest *tc);
+void test_cil_gen_netifcon_extra_nested_secondlist_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_missingobjects_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_secondnested_missingobjects_neg(CuTest *tc);
+void test_cil_gen_netifcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_currnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_astnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_ethmissing_neg(CuTest *tc);
+void test_cil_gen_netifcon_interfacemissing_neg(CuTest *tc);
+void test_cil_gen_netifcon_packetmissing_neg(CuTest *tc);
+
+void test_cil_gen_pirqcon(CuTest *tc);
+void test_cil_gen_pirqcon_pirqnotint_neg(CuTest *tc);
+void test_cil_gen_pirqcon_nopirq_neg(CuTest *tc);
+void test_cil_gen_pirqcon_pirqrange_neg(CuTest *tc);
+void test_cil_gen_pirqcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_pirqcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_pirqcon_extra_neg(CuTest *tc);
+void test_cil_gen_pirqcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_pirqcon_currnull_neg(CuTest *tc);
+void test_cil_gen_pirqcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_iomemcon(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_firstnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_secondnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_empty_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_singleiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_noiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_iomemcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_iomemcon_extra_neg(CuTest *tc);
+void test_cil_gen_iomemcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_iomemcon_currnull_neg(CuTest *tc);
+void test_cil_gen_iomemcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_ioportcon(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_firstnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_secondnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_empty_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_singleioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_noioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_ioportcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_ioportcon_extra_neg(CuTest *tc);
+void test_cil_gen_ioportcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_ioportcon_currnull_neg(CuTest *tc);
+void test_cil_gen_ioportcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_pcidevicecon(CuTest *tc);
+void test_cil_gen_pcidevicecon_pcidevicenotint_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_nopcidevice_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_pcidevicerange_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_nocontext_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_extra_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_currnull_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_fsuse_anoncontext(CuTest *tc);
+void test_cil_gen_fsuse_anoncontext_neg(CuTest *tc);
+void test_cil_gen_fsuse_xattr(CuTest *tc);
+void test_cil_gen_fsuse_task(CuTest *tc);
+void test_cil_gen_fsuse_transition(CuTest *tc);
+void test_cil_gen_fsuse_invalidtype_neg(CuTest *tc);
+void test_cil_gen_fsuse_notype_neg(CuTest *tc);
+void test_cil_gen_fsuse_typeinparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_nofilesystem_neg(CuTest *tc);
+void test_cil_gen_fsuse_filesysteminparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_nocontext_neg(CuTest *tc);
+void test_cil_gen_fsuse_emptyconparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_extra_neg(CuTest *tc);
+void test_cil_gen_fsuse_dbnull_neg(CuTest *tc);
+void test_cil_gen_fsuse_currnull_neg(CuTest *tc);
+void test_cil_gen_fsuse_astnull_neg(CuTest *tc);
+
+void test_cil_gen_macro_noparams(CuTest *tc);
+void test_cil_gen_macro_type(CuTest *tc);
+void test_cil_gen_macro_role(CuTest *tc);
+void test_cil_gen_macro_user(CuTest *tc);
+void test_cil_gen_macro_sensitivity(CuTest *tc);
+void test_cil_gen_macro_category(CuTest *tc);
+void test_cil_gen_macro_catset(CuTest *tc);
+void test_cil_gen_macro_level(CuTest *tc);
+void test_cil_gen_macro_class(CuTest *tc);
+void test_cil_gen_macro_classmap(CuTest *tc);
+void test_cil_gen_macro_permset(CuTest *tc);
+void test_cil_gen_macro_duplicate(CuTest *tc);
+void test_cil_gen_macro_duplicate_neg(CuTest *tc);
+void test_cil_gen_macro_unknown_neg(CuTest *tc);
+void test_cil_gen_macro_dbnull_neg(CuTest *tc);
+void test_cil_gen_macro_currnull_neg(CuTest *tc);
+void test_cil_gen_macro_astnull_neg(CuTest *tc);
+void test_cil_gen_macro_unnamed_neg(CuTest *tc);
+void test_cil_gen_macro_noparam_name_neg(CuTest *tc);
+void test_cil_gen_macro_noparam_neg(CuTest *tc);
+void test_cil_gen_macro_nosecondparam_neg(CuTest *tc);
+void test_cil_gen_macro_emptyparam_neg(CuTest *tc);
+void test_cil_gen_macro_paramcontainsperiod_neg(CuTest *tc);
+
+void test_cil_gen_call(CuTest *tc);
+void test_cil_gen_call_noargs(CuTest *tc);
+void test_cil_gen_call_anon(CuTest *tc);
+void test_cil_gen_call_empty_call_neg(CuTest *tc);
+void test_cil_gen_call_dbnull_neg(CuTest *tc);
+void test_cil_gen_call_currnull_neg(CuTest *tc);
+void test_cil_gen_call_astnull_neg(CuTest *tc);
+void test_cil_gen_call_name_inparens_neg(CuTest *tc);
+void test_cil_gen_call_noname_neg(CuTest *tc);
+
+void test_cil_gen_optional(CuTest *tc);
+void test_cil_gen_optional_emptyoptional(CuTest *tc);
+void test_cil_gen_optional_dbnull_neg(CuTest *tc);
+void test_cil_gen_optional_currnull_neg(CuTest *tc);
+void test_cil_gen_optional_astnull_neg(CuTest *tc);
+void test_cil_gen_optional_unnamed_neg(CuTest *tc);
+void test_cil_gen_optional_extra_neg(CuTest *tc);
+void test_cil_gen_optional_nameinparens_neg(CuTest *tc);
+void test_cil_gen_optional_norule_neg(CuTest *tc);
+
+void test_cil_gen_policycap(CuTest *tc);
+void test_cil_gen_policycap_noname_neg(CuTest *tc);
+void test_cil_gen_policycap_nameinparens_neg(CuTest *tc);
+void test_cil_gen_policycap_extra_neg(CuTest *tc);
+void test_cil_gen_policycap_dbnull_neg(CuTest *tc);
+void test_cil_gen_policycap_currnull_neg(CuTest *tc);
+void test_cil_gen_policycap_astnull_neg(CuTest *tc);
+
+void test_cil_gen_ipaddr_ipv4(CuTest *tc);
+void test_cil_gen_ipaddr_ipv4_neg(CuTest *tc);
+void test_cil_gen_ipaddr_ipv6(CuTest *tc);
+void test_cil_gen_ipaddr_ipv6_neg(CuTest *tc);
+void test_cil_gen_ipaddr_noname_neg(CuTest *tc);
+void test_cil_gen_ipaddr_nameinparens_neg(CuTest *tc);
+void test_cil_gen_ipaddr_noip_neg(CuTest *tc);
+void test_cil_gen_ipaddr_ipinparens_neg(CuTest *tc);
+void test_cil_gen_ipaddr_extra_neg(CuTest *tc);
+void test_cil_gen_ipaddr_dbnull_neg(CuTest *tc);
+void test_cil_gen_ipaddr_currnull_neg(CuTest *tc);
+void test_cil_gen_ipaddr_astnull_neg(CuTest *tc);
+/*
+cil_build_ast test cases
+*/
+void test_cil_build_ast(CuTest *);
+void test_cil_build_ast_dbnull_neg(CuTest *);
+void test_cil_build_ast_astnull_neg(CuTest *);
+void test_cil_build_ast_suberr_neg(CuTest *);
+void test_cil_build_ast_treenull_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_block(CuTest *);
+void test_cil_build_ast_node_helper_block_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_blockinherit(CuTest *);
+void test_cil_build_ast_node_helper_blockinherit_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_permset(CuTest *);
+void test_cil_build_ast_node_helper_permset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_in(CuTest *);
+void test_cil_build_ast_node_helper_in_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_class(CuTest *);
+void test_cil_build_ast_node_helper_class_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classpermset(CuTest *);
+void test_cil_build_ast_node_helper_classpermset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classmap(CuTest *);
+void test_cil_build_ast_node_helper_classmap_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classmapping(CuTest *);
+void test_cil_build_ast_node_helper_classmapping_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_common(CuTest *);
+void test_cil_build_ast_node_helper_common_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sid(CuTest *);
+void test_cil_build_ast_node_helper_sid_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sidcontext(CuTest *);
+void test_cil_build_ast_node_helper_sidcontext_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_user(CuTest *);
+void test_cil_build_ast_node_helper_user_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userlevel(CuTest *);
+void test_cil_build_ast_node_helper_userlevel_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userrange(CuTest *);
+void test_cil_build_ast_node_helper_userrange_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type(CuTest *);
+void test_cil_build_ast_node_helper_type_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typeattribute(CuTest *);
+void test_cil_build_ast_node_helper_typeattribute_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_boolif(CuTest *);
+void test_cil_build_ast_node_helper_boolif_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_tunif(CuTest *);
+void test_cil_build_ast_node_helper_tunif_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_condblock_true(CuTest *);
+void test_cil_build_ast_node_helper_condblock_true_neg(CuTest *);
+void test_cil_build_ast_node_helper_condblock_false(CuTest *);
+void test_cil_build_ast_node_helper_condblock_false_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typealias(CuTest *);
+void test_cil_build_ast_node_helper_typealias_notype_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typebounds(CuTest *);
+void test_cil_build_ast_node_helper_typebounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typepermissive(CuTest *);
+void test_cil_build_ast_node_helper_typepermissive_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_nametypetransition(CuTest *);
+void test_cil_build_ast_node_helper_nametypetransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_rangetransition(CuTest *);
+void test_cil_build_ast_node_helper_rangetransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typeattributeset(CuTest *);
+void test_cil_build_ast_node_helper_typeattributeset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userbounds(CuTest *);
+void test_cil_build_ast_node_helper_userbounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_role(CuTest *);
+void test_cil_build_ast_node_helper_role_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_roletransition(CuTest *);
+void test_cil_build_ast_node_helper_roletransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_roleallow(CuTest *);
+void test_cil_build_ast_node_helper_roleallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_rolebounds(CuTest *);
+void test_cil_build_ast_node_helper_rolebounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_allow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_allow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_auditallow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_auditallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_dontaudit(CuTest *);
+void test_cil_build_ast_node_helper_avrule_dontaudit_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_neverallow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_neverallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_transition(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_transition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_change(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_change_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_member(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_member_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_bool(CuTest *);
+void test_cil_build_ast_node_helper_bool_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_bool_tunable(CuTest *);
+void test_cil_build_ast_node_helper_bool_tunable_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_else(CuTest *);
+void test_cil_build_ast_node_helper_else_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sensitivity(CuTest *);
+void test_cil_build_ast_node_helper_sensitivity_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sensalias(CuTest *);
+void test_cil_build_ast_node_helper_sensalias_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_category(CuTest *);
+void test_cil_build_ast_node_helper_category_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_catset(CuTest *tc);
+void test_cil_build_ast_node_helper_catset_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catorder(CuTest *tc);
+void test_cil_build_ast_node_helper_catorder_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catalias(CuTest *tc);
+void test_cil_build_ast_node_helper_catalias_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catrange(CuTest *tc);
+void test_cil_build_ast_node_helper_catrange_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_roletype(CuTest *tc);
+void test_cil_build_ast_node_helper_roletype_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_userrole(CuTest *tc);
+void test_cil_build_ast_node_helper_userrole_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_classcommon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_classcommon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_dominance(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_dominance_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_senscat(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_senscat_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_level(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_level_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_levelrange(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_levelrange_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_constrain(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_constrain_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_mlsconstrain(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_mlsconstrain_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_context(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_context_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_filecon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_filecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_portcon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_portcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_nodecon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_nodecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_genfscon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_genfscon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_netifcon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_netifcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_pirqcon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_pirqcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_iomemcon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_iomemcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_ioportcon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_ioportcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_pcidevicecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_fsuse(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_fsuse_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_macro(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_macro_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_macro_nested_macro_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_call(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_call_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_optional(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_optional_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_policycap(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_policycap_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_ipaddr(CuTest *tc); 
+void test_cil_build_ast_node_helper_gen_ipaddr_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_extraargsnull_neg(CuTest *);
+
+void test_cil_build_ast_last_child_helper(CuTest *);
+void test_cil_build_ast_last_child_helper_extraargsnull_neg(CuTest *);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_copy_ast.c b/libsepol/cil/test/unit/test_cil_copy_ast.c
new file mode 100644
index 0000000..0053e85
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_copy_ast.c
@@ -0,0 +1,2571 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_copy_ast.h"
+#include "../../src/cil_build_ast.h"
+#include "../../src/cil_resolve_ast.h"
+
+#define CIL_TEST_SYM_SIZE	1
+
+int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args);
+
+struct cil_args_copy {
+	struct cil_tree_node *dest;
+	struct cil_db *db;
+};
+
+struct cil_args_copy *gen_copy_args(struct cil_tree_node *node, struct cil_db *db)
+{
+	struct cil_args_copy *args = cil_malloc(sizeof(*args));
+	args->dest = node;
+	args->db = db;
+
+	return args;
+}
+
+void test_cil_copy_list(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	struct cil_list *cil_l;
+
+	gen_test_tree(&test_tree, line);
+	cil_list_init(&cil_l);
+
+	cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+	struct cil_list *copy_list;
+	cil_list_init(&copy_list);
+
+	int rc =cil_copy_list(cil_l, &copy_list);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+	CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+	CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+	CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+}
+
+void test_cil_copy_list_sublist(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	struct cil_list *cil_l;
+
+	gen_test_tree(&test_tree, line);
+	cil_list_init(&cil_l);
+
+	cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+	struct cil_list *copy_list;
+	cil_list_init(&copy_list);
+
+	int rc = cil_copy_list(cil_l, &copy_list);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+	CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+	CuAssertStrEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->data, ((struct cil_list *)cil_l->head->next->next->data)->head->data);
+	CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+	CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+	CuAssertIntEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->flavor, ((struct cil_list *)cil_l->head->next->next->data)->head->flavor);
+}
+
+void test_cil_copy_list_sublist_extra(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", "foo4", ")", NULL};
+
+	struct cil_tree *test_tree;
+	struct cil_list *cil_l;
+
+	gen_test_tree(&test_tree, line);
+	cil_list_init(&cil_l);
+
+	cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+	struct cil_list *copy_list;
+	cil_list_init(&copy_list);
+
+	int rc = cil_copy_list(cil_l, &copy_list);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+	CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+	CuAssertStrEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->data, ((struct cil_list *)cil_l->head->next->next->data)->head->data);
+	CuAssertStrEquals(tc, copy_list->head->next->next->next->data, cil_l->head->next->next->next->data);
+	CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+	CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+	CuAssertIntEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->flavor, ((struct cil_list *)cil_l->head->next->next->data)->head->flavor);
+	CuAssertIntEquals(tc, copy_list->head->next->next->next->flavor, cil_l->head->next->next->next->flavor);
+}
+
+void test_cil_copy_list_orignull_neg(CuTest *tc) {
+	char *line[] = {"(", "foo1", "foo2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	struct cil_list *cil_l = NULL;
+
+	gen_test_tree(&test_tree, line);
+
+	struct cil_list *copy_list;
+	cil_list_init(&copy_list);
+
+	int rc = cil_copy_list(cil_l, &copy_list);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+	CuAssertPtrEquals(tc, copy_list->head, NULL);
+}
+
+void test_cil_copy_block(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK][CIL_SYM_BLOCKS]);
+
+	int rc = cil_copy_block(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_perm(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_class *new_node;
+	cil_class_init(&new_node);
+
+	struct cil_tree_node *new_tree_node;
+	cil_tree_node_init(&new_tree_node);
+	new_tree_node->data = new_node;
+	new_tree_node->flavor = CIL_CLASS;
+
+	test_ast_node->parent = new_tree_node;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+	cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+	int rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next, test_ast_node);
+	rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next->next, test_ast_node);
+	rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	
+}
+
+void test_cil_copy_class(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+	int rc = cil_copy_class(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_common(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+	int rc = cil_copy_common(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_classcommon(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        char *test_key = test_tree->root->cl_head->cl_head->next->data;
+        struct cil_class *test_cls;
+	cil_class_init(&test_cls);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+        test_ast_node->data = test_cls;
+        test_ast_node->flavor = CIL_CLASS;
+
+        cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_classcommon *test_copy;
+	cil_classcommon_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+	int rc = cil_copy_classcommon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_classcommon *)test_ast_node->data)->class_str, test_copy->class_str);
+	CuAssertStrEquals(tc, ((struct cil_classcommon *)test_ast_node->data)->common_str, test_copy->common_str);
+}
+
+void test_cil_copy_sid(CuTest *tc) {
+	char *line[] = {"(", "sid", "test", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_sid(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_sidcontext(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_user *)test_copy->data)->datum.name, 
+		((struct cil_user *)test_ast_node->data)->datum.name);
+}
+
+void test_cil_copy_user(CuTest *tc) {
+	char *line[] = {"(", "user", "sysadm", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_user(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_role(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_role(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_userrole(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_userrole *test_copy;
+	cil_userrole_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_userrole(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_userrole *)test_ast_node->data)->user_str, test_copy->user_str);
+	CuAssertStrEquals(tc, ((struct cil_userrole *)test_ast_node->data)->role_str, test_copy->role_str);
+}
+
+void test_cil_copy_type(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_type(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_typealias(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_typealias(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_typeattribute(CuTest *tc) {
+	char *line[] = {"(", "typettribute", "type_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_typeattribute(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_bool(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_bool(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertIntEquals(tc, ((struct cil_bool *)test_copy->data)->value,
+		((struct cil_bool *)test_ast_node->data)->value);
+}
+
+void test_cil_copy_type_rule(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+
+	struct cil_type_rule *test_copy;
+	cil_type_rule_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_type_rule(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertIntEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->rule_kind, test_copy->rule_kind);
+	CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->src_str, test_copy->src_str);
+	CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->tgt_str, test_copy->tgt_str);
+	CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->obj_str, test_copy->obj_str);
+}
+
+void test_cil_copy_avrule(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+
+	struct cil_avrule *test_copy;
+	cil_avrule_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_avrule(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->rule_kind, test_copy->rule_kind);
+	CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->src_str, test_copy->src_str);
+	CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->tgt_str, test_copy->tgt_str);
+	CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->class_str, test_copy->classpermset->class_str);
+	CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->flavor, test_copy->classpermset->permset->perms_list_str->head->flavor);
+	CuAssertStrEquals(tc, (char*)((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->data, (char*)test_copy->classpermset->permset->perms_list_str->head->data);
+	CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->next->flavor, test_copy->classpermset->permset->perms_list_str->head->next->flavor);
+	CuAssertStrEquals(tc, (char*)((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->next->data, (char*)test_copy->classpermset->permset->perms_list_str->head->next->data);
+}
+
+void test_cil_copy_sens(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_sens(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_sensalias(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_sensalias *)test_copy->data)->sens_str,
+		((struct cil_sensalias *)test_ast_node->data)->sens_str);
+}
+
+void test_cil_copy_cat(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_cat(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_catalias(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+	
+	cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_catalias(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_catalias *)test_copy->data)->cat_str,
+		((struct cil_catalias *)test_ast_node->data)->cat_str);
+}
+
+void test_cil_copy_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+
+	struct cil_senscat *test_copy;
+	cil_senscat_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_senscat(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_senscat *)test_ast_node->data)->sens_str, test_copy->sens_str);
+	CuAssertStrEquals(tc, (char*)((struct cil_senscat *)test_ast_node->data)->catset->cat_list_str->head->data,
+	                      (char*)test_copy->catset->cat_list_str->head->data);
+	CuAssertStrEquals(tc, (char*)((struct cil_senscat *)test_ast_node->data)->catset->cat_list_str->head->next->data,
+	                      (char*)test_copy->catset->cat_list_str->head->next->data);
+}
+
+void test_cil_copy_catorder(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+
+	struct cil_catorder *test_copy;
+	cil_catorder_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_catorder(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, (char*)((struct cil_catorder *)test_ast_node->data)->cat_list_str->head->data, (char*)test_copy->cat_list_str->head->data);
+	CuAssertStrEquals(tc, (char*)((struct cil_catorder *)test_ast_node->data)->cat_list_str->head->next->data, (char*)test_copy->cat_list_str->head->next->data);
+}
+
+void test_cil_copy_dominance(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "sensitivity", "s2", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+
+	struct cil_sens_dominates *test_copy;
+	cil_sens_dominates_init(&test_copy);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_dominance(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, (char*)((struct cil_sens_dominates *)test_ast_node->data)->sens_list_str->head->data, (char*)test_copy->sens_list_str->head->data);
+	CuAssertStrEquals(tc, (char*)((struct cil_sens_dominates *)test_ast_node->data)->sens_list_str->head->next->data, (char*)test_copy->sens_list_str->head->next->data);
+}
+
+void test_cil_copy_level(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_level(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_fill_level(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+	cil_level_init((struct cil_level**)&test_copy->data);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_fill_level((struct cil_level*)test_ast_node->data, (struct cil_level*)test_copy->data);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_level *)test_copy->data)->sens_str,
+		((struct cil_level *)test_ast_node->data)->sens_str);
+}
+
+void test_cil_copy_context(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_context(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_netifcon(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_netifcon *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_netifcon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, test_copy->interface_str, 
+		((struct cil_netifcon *)test_ast_node->data)->interface_str);
+	CuAssertStrEquals(tc, test_copy->if_context_str,
+		((struct cil_netifcon *)test_ast_node->data)->if_context_str);
+	CuAssertStrEquals(tc, test_copy->packet_context_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context_str);
+}
+
+void test_cil_copy_netifcon_nested(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1", 
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+			"(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_netifcon *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_netifcon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, test_copy->interface_str, 
+		((struct cil_netifcon *)test_ast_node->data)->interface_str);
+	CuAssertStrEquals(tc, test_copy->if_context_str,
+		((struct cil_netifcon *)test_ast_node->data)->if_context_str);
+	CuAssertStrEquals(tc, test_copy->packet_context_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context_str);
+	CuAssertStrEquals(tc, test_copy->packet_context->user_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context->user_str);
+	CuAssertStrEquals(tc, test_copy->packet_context->role_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context->role_str);
+	CuAssertStrEquals(tc, test_copy->packet_context->type_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context->type_str);
+	CuAssertStrEquals(tc, test_copy->packet_context->range_str,
+		((struct cil_netifcon *)test_ast_node->data)->packet_context->range_str);
+}
+
+void test_cil_copy_fill_context(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "range", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+	cil_context_init((struct cil_context**)&test_copy->data);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_fill_context((struct cil_context*)test_ast_node->data, (struct cil_context*)test_copy->data);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->user_str,
+		((struct cil_context *)test_ast_node->data)->user_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->role_str,
+		((struct cil_context *)test_ast_node->data)->role_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->type_str,
+		((struct cil_context *)test_ast_node->data)->type_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->range_str,
+		((struct cil_context *)test_ast_node->data)->range_str);
+}
+
+void test_cil_copy_fill_context_anonrange(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+	cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+	cil_context_init((struct cil_context**)&test_copy->data);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_fill_context((struct cil_context*)test_ast_node->data, (struct cil_context*)test_copy->data);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->user_str,
+		((struct cil_context *)test_ast_node->data)->user_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->role_str,
+		((struct cil_context *)test_ast_node->data)->role_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->type_str,
+		((struct cil_context *)test_ast_node->data)->type_str);
+	CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->range_str,
+		((struct cil_context *)test_ast_node->data)->range_str);
+}
+
+void test_cil_copy_call(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_call *test_copy;
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_call(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, test_copy->macro_str, ((struct cil_call *)test_ast_node->data)->macro_str);
+}
+
+void test_cil_copy_optional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_optional(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_nodecon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_nodecon *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_nodecon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, test_copy->addr_str,
+		((struct cil_nodecon *)test_ast_node->data)->addr_str);
+	CuAssertStrEquals(tc, test_copy->mask_str,
+		((struct cil_nodecon *)test_ast_node->data)->mask_str);
+	CuAssertStrEquals(tc, test_copy->context_str,
+		((struct cil_nodecon *)test_ast_node->data)->context_str);
+}
+
+void test_cil_copy_nodecon_anon(CuTest *tc) {
+	char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "(", "192.168.1.1", ")", "(", "user", "role", "type", "(", "low", "high", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_nodecon *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_nodecon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, test_copy->addr_str,
+		((struct cil_nodecon *)test_ast_node->data)->addr_str);
+	CuAssertStrEquals(tc, test_copy->mask_str,
+		((struct cil_nodecon *)test_ast_node->data)->mask_str);
+	CuAssertStrEquals(tc, test_copy->context_str,
+		((struct cil_nodecon *)test_ast_node->data)->context_str);
+}
+
+void test_cil_copy_fill_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	struct cil_ipaddr *new;
+	cil_ipaddr_init(&new);
+	struct cil_ipaddr *old;
+	cil_ipaddr_init(&new);
+
+	old = (struct cil_ipaddr*)test_ast_node->data;
+	int rc = cil_copy_fill_ipaddr(old, new);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+
+	CuAssertIntEquals(tc, old->family, new->family);
+}
+
+void test_cil_copy_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_tree_node *test_copy;
+	cil_tree_node_init(&test_copy);
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_ipaddr(test_db, test_ast_node->data, &test_copy->data, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_conditional(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_list_item *curr_old;
+	curr_old = ((struct cil_booleanif*)test_ast_node->data)->expr_stack->head;
+
+	struct cil_conditional *cond_new;
+
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_conditional(test_db, curr_old->data, (void**)&cond_new, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+
+	CuAssertStrEquals(tc, ((struct cil_conditional*)curr_old->data)->str, cond_new->str);
+	CuAssertIntEquals(tc, ((struct cil_conditional*)curr_old->data)->flavor, cond_new->flavor);
+}
+
+void test_cil_copy_boolif(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+	struct cil_booleanif *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_boolif(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_constrain(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+	struct cil_constrain *test_copy;
+	
+	symtab_t sym;
+	symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+	int rc = cil_copy_constrain(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+	CuAssertStrEquals(tc, ((struct cil_constrain*)test_copy)->classpermset->class_str, ((struct cil_constrain *)test_ast_node->data)->classpermset->class_str);
+}
+/*
+void test_cil_copy_ast(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *test_copy;
+	cil_constrain_init(&test_copy);
+	cil_list_init(&test_copy->expr);
+
+	int rc = cil_copy_ast(((struct cil_constrain *)test_ast_node->data)->expr, test_copy->expr);
+	CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_ast_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", ")", NULL};
+	
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_tree_node *test_ast_node;
+        cil_tree_node_init(&test_ast_node);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+        test_ast_node->parent = test_db->ast->root;
+        test_ast_node->line = 1;
+
+        cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+	struct cil_tree_node *test_current;
+	test_current = test_tree->root->cl_head->cl_head;
+
+	struct cil_constrain *test_copy;
+	cil_constrain_init(&test_copy);
+	cil_list_init(&test_copy->expr);
+
+	int rc = cil_copy_ast(((struct cil_constrain *)test_ast_node->data)->expr, test_copy->expr);
+	CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+*/
+/* node_helper functions */
+
+void test_cil_copy_node_helper_block(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_block_merge(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_perm(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_class *test_class;
+	cil_class_init(&test_class);
+	
+	struct cil_tree_node *parent_node;
+	cil_tree_node_init(&parent_node);
+	parent_node->flavor = CIL_CLASS;
+	parent_node->data = test_class;
+	struct cil_tree_node *root;
+	cil_tree_node_init(&root);
+	root->flavor = CIL_ROOT;
+	parent_node->parent = root;
+
+	struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_perm_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_class(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_class_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "test", "(", "read", "write", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_common(CuTest *tc) {
+	char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_common_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_classcommon(CuTest *tc) {
+	char *line[] = {"(", "classcommon", "file", "file", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sid(CuTest *tc) {
+	char *line[] = {"(", "sid", "test", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sid_merge(CuTest *tc) {
+	char *line[] = {"(", "sid", "test", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_user(CuTest *tc) {
+	char *line[] = {"(", "user", "sysadm", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_user_merge(CuTest *tc) {
+	char *line[] = {"(", "user", "sysadm", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_role(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_role_merge(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_userrole(CuTest *tc) {
+	char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type(CuTest *tc) {
+	char *line[] = {"(", "type", "type_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type_merge(CuTest *tc) {
+	char *line[] = {"(", "type", "type_t", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typeattribute(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typeattribute_merge(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "bar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typealias(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typealias_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_bool(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_bool_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_avrule(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "file", "(", "read", "write", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type_rule(CuTest *tc) {
+	char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sens(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sens_merge(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sensalias_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_cat(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_cat_merge(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catalias(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catalias_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+			"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_senscat *test_senscat;
+	cil_senscat_init(&test_senscat);
+	
+	struct cil_tree_node *parent_node;
+	cil_tree_node_init(&parent_node);
+	parent_node->flavor = CIL_SENSCAT;
+	parent_node->data = test_senscat;
+
+	struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catorder(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c255", ")",
+			"(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_catorder *test_catorder;
+	cil_catorder_init(&test_catorder);
+	
+	struct cil_tree_node *parent_node;
+	cil_tree_node_init(&parent_node);
+	parent_node->flavor = CIL_CATORDER;
+	parent_node->data = test_catorder;
+
+	struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_dominance(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "sensitivity", "s2", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_sens *test_sens;
+	cil_sens_init(&test_sens);
+	
+	struct cil_tree_node *parent_node;
+	cil_tree_node_init(&parent_node);
+	parent_node->flavor = CIL_SENS;
+	parent_node->data = test_sens;
+
+	struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_level(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_level_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_context(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_context_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")",  ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_netifcon(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_call(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_optional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_optional_merge(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_ipaddr_dup_neg(CuTest *tc) {
+	char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_boolif(CuTest *tc) {
+	char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true", 
+			"(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_mlsconstrain(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, finished, 0);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_orignull_neg(CuTest *tc) {
+	char *line[] = {"(", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	uint32_t finished = 0;
+
+	struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_extraargsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_db *test_db2;
+	cil_db_init(&test_db2);
+
+	struct cil_args_copy *extra_args = NULL;
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_copy_ast.h b/libsepol/cil/test/unit/test_cil_copy_ast.h
new file mode 100644
index 0000000..b1aace1
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_copy_ast.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_COPY_AST_H_
+#define TEST_CIL_COPY_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_copy_list(CuTest *);
+void test_cil_copy_list_sublist(CuTest *);
+void test_cil_copy_list_sublist_extra(CuTest *);
+void test_cil_copy_list_orignull_neg(CuTest *);
+
+void test_cil_copy_block(CuTest *);
+void test_cil_copy_node_helper_block(CuTest *tc); 
+void test_cil_copy_node_helper_block_merge(CuTest *tc); 
+
+void test_cil_copy_perm(CuTest *);
+void test_cil_copy_node_helper_perm(CuTest *tc); 
+void test_cil_copy_node_helper_perm_neg(CuTest *tc); 
+
+void test_cil_copy_class(CuTest *);
+void test_cil_copy_node_helper_class(CuTest *tc); 
+void test_cil_copy_node_helper_class_dup_neg(CuTest *tc); 
+
+void test_cil_copy_common(CuTest *);
+void test_cil_copy_node_helper_common(CuTest *tc); 
+void test_cil_copy_node_helper_common_dup_neg(CuTest *tc); 
+
+void test_cil_copy_classcommon(CuTest *);
+void test_cil_copy_node_helper_classcommon(CuTest *tc); 
+
+void test_cil_copy_sid(CuTest *);
+void test_cil_copy_node_helper_sid(CuTest *tc); 
+void test_cil_copy_node_helper_sid_merge(CuTest *tc); 
+
+void test_cil_copy_sidcontext(CuTest *);
+void test_cil_copy_node_helper_sidcontext(CuTest *tc); 
+
+void test_cil_copy_user(CuTest *);
+void test_cil_copy_node_helper_user(CuTest *tc); 
+void test_cil_copy_node_helper_user_merge(CuTest *tc); 
+
+void test_cil_copy_role(CuTest *);
+void test_cil_copy_node_helper_role(CuTest *tc); 
+void test_cil_copy_node_helper_role_merge(CuTest *tc); 
+
+void test_cil_copy_userrole(CuTest *);
+void test_cil_copy_node_helper_userrole(CuTest *tc); 
+
+void test_cil_copy_type(CuTest *);
+void test_cil_copy_node_helper_type(CuTest *tc); 
+void test_cil_copy_node_helper_type_merge(CuTest *tc); 
+
+void test_cil_copy_typeattribute(CuTest *);
+void test_cil_copy_node_helper_typeattribute(CuTest *tc); 
+void test_cil_copy_node_helper_typeattribute_merge(CuTest *tc); 
+
+void test_cil_copy_typealias(CuTest *);
+void test_cil_copy_node_helper_typealias(CuTest *tc); 
+void test_cil_copy_node_helper_typealias_dup_neg(CuTest *tc); 
+
+void test_cil_copy_bool(CuTest *);
+void test_cil_copy_node_helper_bool(CuTest *tc); 
+void test_cil_copy_node_helper_bool_dup_neg(CuTest *tc); 
+
+void test_cil_copy_avrule(CuTest *);
+void test_cil_copy_node_helper_avrule(CuTest *tc); 
+
+void test_cil_copy_type_rule(CuTest *);
+void test_cil_copy_node_helper_type_rule(CuTest *tc); 
+
+void test_cil_copy_sens(CuTest *);
+void test_cil_copy_node_helper_sens(CuTest *tc); 
+void test_cil_copy_node_helper_sens_merge(CuTest *tc); 
+
+void test_cil_copy_sensalias(CuTest *);
+void test_cil_copy_node_helper_sensalias(CuTest *tc); 
+void test_cil_copy_node_helper_sensalias_dup_neg(CuTest *tc); 
+
+void test_cil_copy_cat(CuTest *);
+void test_cil_copy_node_helper_cat(CuTest *tc); 
+void test_cil_copy_node_helper_cat_merge(CuTest *tc); 
+
+void test_cil_copy_catalias(CuTest *);
+void test_cil_copy_node_helper_catalias(CuTest *tc); 
+void test_cil_copy_node_helper_catalias_dup_neg(CuTest *tc); 
+
+void test_cil_copy_senscat(CuTest *);
+void test_cil_copy_node_helper_senscat(CuTest *tc); 
+
+void test_cil_copy_catorder(CuTest *);
+void test_cil_copy_node_helper_catorder(CuTest *tc); 
+
+void test_cil_copy_dominance(CuTest *);
+void test_cil_copy_node_helper_dominance(CuTest *tc); 
+
+void test_cil_copy_level(CuTest *);
+void test_cil_copy_node_helper_level(CuTest *tc); 
+void test_cil_copy_node_helper_level_dup_neg(CuTest *tc); 
+
+void test_cil_copy_fill_level(CuTest *);
+
+void test_cil_copy_context(CuTest *);
+void test_cil_copy_node_helper_context(CuTest *tc); 
+void test_cil_copy_node_helper_context_dup_neg(CuTest *tc); 
+
+void test_cil_copy_netifcon(CuTest *);
+void test_cil_copy_netifcon_nested(CuTest *);
+void test_cil_copy_node_helper_netifcon(CuTest *tc); 
+void test_cil_copy_node_helper_netifcon_merge(CuTest *tc); 
+
+void test_cil_copy_fill_context(CuTest *);
+void test_cil_copy_fill_context_anonrange(CuTest *);
+
+void test_cil_copy_call(CuTest *);
+void test_cil_copy_node_helper_call(CuTest *tc); 
+
+void test_cil_copy_optional(CuTest *);
+void test_cil_copy_node_helper_optional(CuTest *tc); 
+void test_cil_copy_node_helper_optional_merge(CuTest *tc); 
+
+void test_cil_copy_nodecon(CuTest *);
+void test_cil_copy_nodecon_anon(CuTest *);
+
+void test_cil_copy_fill_ipaddr(CuTest *);
+
+void test_cil_copy_ipaddr(CuTest *);
+void test_cil_copy_node_helper_ipaddr(CuTest *tc); 
+void test_cil_copy_node_helper_ipaddr_dup_neg(CuTest *tc); 
+
+void test_cil_copy_conditional(CuTest *);
+
+void test_cil_copy_boolif(CuTest *);
+void test_cil_copy_node_helper_boolif(CuTest *tc); 
+
+void test_cil_copy_constrain(CuTest *);
+void test_cil_copy_node_helper_mlsconstrain(CuTest *tc); 
+
+void test_cil_copy_ast(CuTest *);
+void test_cil_copy_ast_neg(CuTest *);
+
+void test_cil_copy_node_helper_orignull_neg(CuTest *tc); 
+void test_cil_copy_node_helper_extraargsnull_neg(CuTest *tc); 
+
+void test_cil_copy_data_helper(CuTest *tc); 
+void test_cil_copy_data_helper_getparentsymtab_neg(CuTest *tc); 
+void test_cil_copy_data_helper_duplicatedb_neg(CuTest *tc); 
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_fqn.c b/libsepol/cil/test/unit/test_cil_fqn.c
new file mode 100644
index 0000000..4304fc1
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_fqn.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_fqn.h"
+#include "../../src/cil_build_ast.h"
+
+void test_cil_qualify_name(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "sid", "test", "con", NULL};
+
+	struct cil_tree *tree;
+	gen_test_tree(&tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, tree->root, test_db->ast->root);
+
+	int rc = cil_fqn_qualify(test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_qualify_name_cil_flavor(CuTest *tc) {
+	char *line[] = {"(", "class",  "file", "inherits", "file",
+			"(", "open", ")", ")", NULL};
+
+	struct cil_tree *tree;
+	gen_test_tree(&tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, tree->root, test_db->ast->root);
+
+	int rc = cil_fqn_qualify(test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_fqn.h b/libsepol/cil/test/unit/test_cil_fqn.h
new file mode 100644
index 0000000..93f0ffd
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_fqn.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_FQN_H_
+#define TEST_CIL_FQN_H_
+
+#include "CuTest.h"
+
+void test_cil_qualify_name(CuTest *);
+void test_cil_qualify_name_cil_flavor(CuTest *tc);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_lexer.c b/libsepol/cil/test/unit/test_cil_lexer.c
new file mode 100644
index 0000000..011afef
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_lexer.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_lexer.h"
+
+#include "../../src/cil_lexer.h"
+
+void test_cil_lexer_setup(CuTest *tc) {
+   char *test_str = "(test \"qstring\");comment\n";
+   uint32_t str_size = strlen(test_str);
+   char *buffer = malloc(str_size + 2);
+
+   memset(buffer+str_size, 0, 2);
+   strncpy(buffer, test_str, str_size);
+
+   int rc = cil_lexer_setup(buffer, str_size + 2);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+   free(buffer);
+}
+
+void test_cil_lexer_next(CuTest *tc) {
+   char *test_str = "(test \"qstring\") ;comment\n";
+   uint32_t str_size = strlen(test_str);
+   char *buffer = malloc(str_size + 2);
+
+   memset(buffer+str_size, 0, 2);
+   strcpy(buffer, test_str);
+
+   cil_lexer_setup(buffer, str_size + 2);
+
+   struct token test_tok;
+
+   int rc = cil_lexer_next(&test_tok);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+   CuAssertIntEquals(tc, OPAREN, test_tok.type);
+   CuAssertStrEquals(tc, "(", test_tok.value);
+   CuAssertIntEquals(tc, 1, test_tok.line);
+
+   rc = cil_lexer_next(&test_tok);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+   
+   CuAssertIntEquals(tc, SYMBOL, test_tok.type);
+   CuAssertStrEquals(tc, "test", test_tok.value);
+   CuAssertIntEquals(tc, 1, test_tok.line);
+ 
+   rc = cil_lexer_next(&test_tok);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+   
+   CuAssertIntEquals(tc, QSTRING, test_tok.type);
+   CuAssertStrEquals(tc, "\"qstring\"", test_tok.value);
+   CuAssertIntEquals(tc, 1, test_tok.line);
+ 
+   rc = cil_lexer_next(&test_tok);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+   
+   CuAssertIntEquals(tc, CPAREN, test_tok.type);
+   CuAssertStrEquals(tc, ")", test_tok.value);
+   CuAssertIntEquals(tc, 1, test_tok.line);
+
+   rc = cil_lexer_next(&test_tok);
+   CuAssertIntEquals(tc, SEPOL_OK, rc);
+  
+   CuAssertIntEquals(tc, COMMENT, test_tok.type);
+   CuAssertStrEquals(tc, ";comment", test_tok.value);
+   CuAssertIntEquals(tc, 1, test_tok.line);
+
+   free(buffer);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_lexer.h b/libsepol/cil/test/unit/test_cil_lexer.h
new file mode 100644
index 0000000..78a4609
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_lexer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_LEXER_H_
+#define TEST_CIL_LEXER_H_
+
+#include "CuTest.h"
+
+void test_cil_lexer_setup(CuTest *);
+void test_cil_lexer_next(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_list.c b/libsepol/cil/test/unit/test_cil_list.c
new file mode 100644
index 0000000..b7a63af
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_list.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_build_ast.h"
+
+void test_cil_list_init(CuTest *tc) {
+	struct cil_avrule *test_avrule = malloc(sizeof(*test_avrule));
+
+	cil_classpermset_init(&test_avrule->classpermset);
+	cil_permset_init(&test_avrule->classpermset->permset);
+
+	cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+	CuAssertPtrNotNull(tc, test_avrule->classpermset->permset->perms_list_str);
+
+	cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_list_append_item(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_append_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_append_item_append(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_append_item(test_class_list, test_new_item);
+	
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+	
+	int rc2 = cil_list_append_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_list_append_item_append_extra(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", "process", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_append_item(test_class_list, test_new_item);
+	
+	cil_list_item_init(&test_new_item);
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+	
+	int rc2 = cil_list_append_item(test_class_list, test_new_item);
+	
+	cil_list_item_init(&test_new_item);
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next->next;
+	
+	int rc3 = cil_list_append_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_list_append_item_listnull_neg(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list = NULL;
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_append_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_append_item_itemnull_neg(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item = NULL;
+
+	int rc = cil_list_append_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_prepend_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_prepend_item_prepend(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_prepend_item(test_class_list, test_new_item);
+	
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_prepend_item_prepend_neg(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", "process", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	struct cil_list_item *test_new_item_next;
+	cil_list_item_init(&test_new_item_next);
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+	test_new_item->next = test_new_item_next;	
+	
+	int rc = cil_list_prepend_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item_listnull_neg(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list = NULL;
+
+	struct cil_list_item *test_new_item;
+	cil_list_item_init(&test_new_item);
+
+	test_new_item->flavor = CIL_CLASS;
+	test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+	int rc = cil_list_prepend_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item_itemnull_neg(CuTest *tc) {
+        char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	struct cil_list *test_class_list;
+	cil_list_init(&test_class_list);
+
+	struct cil_list_item *test_new_item = NULL;
+
+	int rc = cil_list_prepend_item(test_class_list, test_new_item);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_list.h b/libsepol/cil/test/unit/test_cil_list.h
new file mode 100644
index 0000000..e627683
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_list.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_LIST_H_
+#define TEST_CIL_LIST_H_
+
+#include "CuTest.h"
+
+void test_cil_list_item_init(CuTest *);
+void test_cil_list_append_item(CuTest *);
+void test_cil_list_append_item_append(CuTest *);
+void test_cil_list_append_item_append_extra(CuTest *);
+void test_cil_list_append_item_listnull_neg(CuTest *);
+void test_cil_list_append_item_itemnull_neg(CuTest *);
+void test_cil_list_prepend_item_prepend(CuTest *);
+void test_cil_list_prepend_item_prepend_neg(CuTest *);
+void test_cil_list_prepend_item_listnull_neg(CuTest *);
+void test_cil_list_prepend_item_itemnull_neg(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_parser.c b/libsepol/cil/test/unit/test_cil_parser.c
new file mode 100644
index 0000000..43dc305
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_parser.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_parser.h"
+
+#include "../../src/cil_parser.h"
+#include "../../src/cil_internal.h"
+
+// TODO rewrite to use the gen_tree function
+void test_cil_parser(CuTest *tc) {
+	int rc = 0;
+	struct cil_file_data *data;
+
+	struct cil_tree *test_parse_root;
+	cil_tree_init(&test_parse_root);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	set_cil_file_data(&data);
+
+	rc = cil_parser("policy.cil", data->buffer, data->file_size + 2, &test_parse_root);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_parse_root);
+	// TODO add checking of the parse tree that is returned
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_parser.h b/libsepol/cil/test/unit/test_cil_parser.h
new file mode 100644
index 0000000..2cb280d
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_parser.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_PARSER_H_
+#define TEST_CIL_PARSER_H_
+
+#include "CuTest.h"
+
+void test_cil_parser(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_post.c b/libsepol/cil/test/unit/test_cil_post.c
new file mode 100644
index 0000000..8bb7e76
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_post.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_post.h"
+
+#include "../../src/cil_post.h"
+#include "../../src/cil_internal.h"
+
+void test_cil_post_filecon_compare_meta_a_not_b(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = "ba.r";
+        afilecon->path_str = "foo";
+
+        bfilecon->root_str = "barr";
+        bfilecon->path_str = "foo";
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_meta_b_not_a(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = "bar";
+        afilecon->path_str = "foo";
+
+        bfilecon->root_str = "ba.rr";
+        bfilecon->path_str = "foo";
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = ".\\$";
+        afilecon->path_str = ".$({";
+
+        bfilecon->root_str = ".?";
+        bfilecon->path_str = ".";
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_type_atype_greater_btype(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = ".\\$";
+        afilecon->path_str = ".$({";
+        afilecon->type = CIL_FILECON_CHAR;
+
+        bfilecon->root_str = ".\\$";
+        bfilecon->path_str = ".$({";
+        bfilecon->type = CIL_FILECON_DIR;
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_type_btype_greater_atype(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = ".\\$";
+        afilecon->path_str = ".$({";
+        afilecon->type = CIL_FILECON_DIR;
+
+        bfilecon->root_str = ".\\$";
+        bfilecon->path_str = ".$({";
+        bfilecon->type = CIL_FILECON_CHAR;
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = ".";
+        afilecon->path_str = ".";
+
+        bfilecon->root_str = ".*+|[({";
+        bfilecon->path_str = ".";
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_stemlen_a_greater_b(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = "bar";
+        afilecon->path_str = "foo";
+        
+        bfilecon->root_str = "barr";
+        bfilecon->path_str = "foo";
+        
+        
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc < 0);
+}       
+        
+void test_cil_post_filecon_compare_stemlen_b_greater_a(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+        
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+        
+        afilecon->root_str = "barre";
+        afilecon->path_str = "foo";
+        
+        bfilecon->root_str = "barr";
+        bfilecon->path_str = "foo";
+        
+        
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertTrue(tc, rc > 0);
+}       
+       
+void test_cil_post_filecon_compare_equal(CuTest *tc) {
+        struct cil_filecon *afilecon;
+        cil_filecon_init(&afilecon);
+        
+        struct cil_filecon *bfilecon;
+        cil_filecon_init(&bfilecon);
+
+        afilecon->root_str = ".\\$";
+        afilecon->path_str = ".$({";
+        afilecon->type = CIL_FILECON_DIR;
+
+        bfilecon->root_str = ".\\$";
+        bfilecon->path_str = ".$({";
+        bfilecon->type = CIL_FILECON_DIR;
+
+
+        int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+        CuAssertIntEquals(tc, 0, rc);
+}
+
+void test_cil_post_portcon_compare_atotal_greater_btotal(CuTest *tc) {
+        struct cil_portcon *aportcon;
+        cil_portcon_init(&aportcon);
+
+        struct cil_portcon *bportcon;
+        cil_portcon_init(&bportcon);
+
+        aportcon->port_low = 15;
+        aportcon->port_high = 30;
+
+        bportcon->port_low = 10;
+        bportcon->port_high = 11;
+
+        int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_portcon_compare_btotal_greater_atotal(CuTest *tc) {
+        struct cil_portcon *aportcon;
+        cil_portcon_init(&aportcon);
+
+        struct cil_portcon *bportcon;
+        cil_portcon_init(&bportcon);
+
+        aportcon->port_low = 5;
+        aportcon->port_high = 5;
+
+        bportcon->port_low = 11;
+        bportcon->port_high = 20;
+
+        int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_portcon_compare_aportlow_greater_bportlow(CuTest *tc) {
+        struct cil_portcon *aportcon;
+        cil_portcon_init(&aportcon);
+
+        struct cil_portcon *bportcon;
+        cil_portcon_init(&bportcon);
+
+        aportcon->port_low = 30;
+        aportcon->port_high = 33;
+
+        bportcon->port_low = 17;
+        bportcon->port_high = 20;
+
+        int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_portcon_compare_bportlow_greater_aportlow(CuTest *tc) {
+        struct cil_portcon *aportcon;
+        cil_portcon_init(&aportcon);
+
+        struct cil_portcon *bportcon;
+        cil_portcon_init(&bportcon);
+
+        aportcon->port_low = 5;
+        aportcon->port_high = 8;
+
+        bportcon->port_low = 17;
+        bportcon->port_high = 20;
+
+        int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_portcon_compare_equal(CuTest *tc) {
+        struct cil_portcon *aportcon;
+        cil_portcon_init(&aportcon);
+
+        struct cil_portcon *bportcon;
+        cil_portcon_init(&bportcon);
+
+        aportcon->port_low = 17;
+        aportcon->port_high = 20;
+
+        bportcon->port_low = 17;
+        bportcon->port_high = 20;
+
+        int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+        CuAssertTrue(tc, rc == 0);
+}
+
+void test_cil_post_genfscon_compare_atypestr_greater_btypestr(CuTest *tc) {
+        struct cil_genfscon *agenfscon;
+        cil_genfscon_init(&agenfscon);
+        agenfscon->fs_str = "aaaa";
+
+        struct cil_genfscon *bgenfscon;
+        cil_genfscon_init(&bgenfscon);
+        bgenfscon->fs_str = "bbbb";
+
+        int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_genfscon_compare_btypestr_greater_atypestr(CuTest *tc) {
+        struct cil_genfscon *agenfscon;
+        cil_genfscon_init(&agenfscon);
+        agenfscon->fs_str = "bbbb";
+
+        struct cil_genfscon *bgenfscon;
+        cil_genfscon_init(&bgenfscon);
+        bgenfscon->fs_str = "aaaa";
+
+        int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_genfscon_compare_apathstr_greater_bpathstr(CuTest *tc) {
+        struct cil_genfscon *agenfscon;
+        cil_genfscon_init(&agenfscon);
+        agenfscon->fs_str = "aaaa";
+        agenfscon->path_str = "ff";
+
+        struct cil_genfscon *bgenfscon;
+        cil_genfscon_init(&bgenfscon);
+        bgenfscon->fs_str = "aaaa";
+        bgenfscon->path_str = "gg";
+
+        int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_genfscon_compare_bpathstr_greater_apathstr(CuTest *tc) {
+        struct cil_genfscon *agenfscon;
+        cil_genfscon_init(&agenfscon);
+        agenfscon->fs_str = "bbbb";
+        agenfscon->path_str = "cccc";
+
+        struct cil_genfscon *bgenfscon;
+        cil_genfscon_init(&bgenfscon);
+        bgenfscon->fs_str = "bbbb";
+        bgenfscon->path_str = "aaaa";
+
+        int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_genfscon_compare_equal(CuTest *tc) {
+        struct cil_genfscon *agenfscon;
+        cil_genfscon_init(&agenfscon);
+        agenfscon->fs_str = "bbbb";
+        agenfscon->path_str = "cccc";
+
+        struct cil_genfscon *bgenfscon;
+        cil_genfscon_init(&bgenfscon);
+        bgenfscon->fs_str = "bbbb";
+        bgenfscon->path_str = "cccc";
+
+        int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+        CuAssertIntEquals(tc, 0, rc);
+}
+
+void test_cil_post_netifcon_compare_a_greater_b(CuTest *tc) {
+        struct cil_netifcon *anetifcon;
+        cil_netifcon_init(&anetifcon);
+        anetifcon->interface_str = "aaa";
+
+        struct cil_netifcon *bnetifcon;
+        cil_netifcon_init(&bnetifcon);
+        bnetifcon->interface_str = "bbb";
+
+        int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_netifcon_compare_b_greater_a(CuTest *tc) {
+        struct cil_netifcon *anetifcon;
+        cil_netifcon_init(&anetifcon);
+        anetifcon->interface_str = "bbb";
+
+        struct cil_netifcon *bnetifcon;
+        cil_netifcon_init(&bnetifcon);
+        bnetifcon->interface_str = "aaa";
+
+        int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_netifcon_compare_equal(CuTest *tc) {
+        struct cil_netifcon *anetifcon;
+        cil_netifcon_init(&anetifcon);
+        anetifcon->interface_str = "aaa";
+
+        struct cil_netifcon *bnetifcon;
+        cil_netifcon_init(&bnetifcon);
+        bnetifcon->interface_str = "aaa";
+
+        int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+        CuAssertTrue(tc, rc == 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_bipv6(CuTest *tc) {
+        struct cil_nodecon *anodecon;
+        cil_nodecon_init(&anodecon);
+        cil_ipaddr_init(&anodecon->addr);
+        cil_ipaddr_init(&anodecon->mask);
+
+        struct cil_nodecon *bnodecon;
+        cil_nodecon_init(&bnodecon);
+        cil_ipaddr_init(&bnodecon->addr);
+        cil_ipaddr_init(&bnodecon->mask);
+
+        anodecon->addr->ip.v4.s_addr = 103;
+        anodecon->mask->ip.v4.s_addr = 100;
+        anodecon->addr->family = AF_INET;
+
+        bnodecon->addr->ip.v4.s_addr = 100;
+        bnodecon->mask->ip.v4.s_addr = 100;
+        bnodecon->addr->family = AF_INET6;
+
+        int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_bipv4(CuTest *tc) {
+        struct cil_nodecon *anodecon;
+        cil_nodecon_init(&anodecon);
+        cil_ipaddr_init(&anodecon->addr);
+        cil_ipaddr_init(&anodecon->mask);
+
+        struct cil_nodecon *bnodecon;
+        cil_nodecon_init(&bnodecon);
+        cil_ipaddr_init(&bnodecon->addr);
+        cil_ipaddr_init(&bnodecon->mask);
+
+        anodecon->addr->ip.v4.s_addr = 103;
+        anodecon->mask->ip.v4.s_addr = 100;
+        anodecon->addr->family = AF_INET6;
+
+        bnodecon->addr->ip.v4.s_addr = 100;
+        bnodecon->mask->ip.v4.s_addr = 100;
+        bnodecon->addr->family = AF_INET;
+
+        int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4(CuTest *tc) {
+        struct cil_nodecon *anodecon;
+        cil_nodecon_init(&anodecon);
+        cil_ipaddr_init(&anodecon->addr);
+        cil_ipaddr_init(&anodecon->mask);
+
+        struct cil_nodecon *bnodecon;
+        cil_nodecon_init(&bnodecon);
+        cil_ipaddr_init(&bnodecon->addr);
+        cil_ipaddr_init(&bnodecon->mask);
+
+        anodecon->addr->ip.v4.s_addr = 103;
+        anodecon->mask->ip.v4.s_addr = 100;
+        anodecon->addr->family = AF_INET;
+
+        bnodecon->addr->ip.v4.s_addr = 100;
+        bnodecon->mask->ip.v4.s_addr = 100;
+        bnodecon->addr->family = AF_INET;
+
+        int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+        CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_lessthan_bipv4(CuTest *tc) {
+        struct cil_nodecon *anodecon;
+        cil_nodecon_init(&anodecon);
+        cil_ipaddr_init(&anodecon->addr);
+        cil_ipaddr_init(&anodecon->mask);
+
+        struct cil_nodecon *bnodecon;
+        cil_nodecon_init(&bnodecon);
+        cil_ipaddr_init(&bnodecon->addr);
+        cil_ipaddr_init(&bnodecon->mask);
+
+        anodecon->addr->ip.v4.s_addr = 99;
+        anodecon->mask->ip.v4.s_addr = 100;
+        anodecon->addr->family = AF_INET;
+
+        bnodecon->addr->ip.v4.s_addr = 100;
+        bnodecon->mask->ip.v4.s_addr = 100;
+        bnodecon->addr->family = AF_INET;
+
+        int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+        CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v4.s_addr = 103;
+	anodecon->mask->ip.v4.s_addr = 101;
+	anodecon->addr->family = AF_INET;
+	
+	bnodecon->addr->ip.v4.s_addr = 100;
+	bnodecon->mask->ip.v4.s_addr = 100;
+	bnodecon->addr->family = AF_INET;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v4.s_addr = 99;
+	anodecon->mask->ip.v4.s_addr = 99;
+	anodecon->addr->family = AF_INET;
+	
+	bnodecon->addr->ip.v4.s_addr = 100;
+	bnodecon->mask->ip.v4.s_addr = 100;
+	bnodecon->addr->family = AF_INET;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v6.s6_addr[0] = '5';
+	anodecon->mask->ip.v6.s6_addr[0] = '9';
+	anodecon->addr->family = AF_INET6;
+	
+	bnodecon->addr->ip.v6.s6_addr[0] = '3';
+	bnodecon->mask->ip.v6.s6_addr[0] = '9';
+	bnodecon->addr->family = AF_INET6;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_lessthan_bipv6(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v6.s6_addr[0] = '3';
+	anodecon->mask->ip.v6.s6_addr[0] = '1';
+	anodecon->addr->family = AF_INET6;
+	
+	bnodecon->addr->ip.v6.s6_addr[0] = '5';
+	bnodecon->mask->ip.v6.s6_addr[0] = '1';
+	bnodecon->addr->family = AF_INET6;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v6.s6_addr[0] = '1';
+	anodecon->mask->ip.v6.s6_addr[0] = '4';
+	anodecon->addr->family = AF_INET6;
+	
+	bnodecon->addr->ip.v6.s6_addr[0] = '1';
+	bnodecon->mask->ip.v6.s6_addr[0] = '3';
+	bnodecon->addr->family = AF_INET6;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6(CuTest *tc) {
+	struct cil_nodecon *anodecon;
+	cil_nodecon_init(&anodecon);
+	cil_ipaddr_init(&anodecon->addr);
+	cil_ipaddr_init(&anodecon->mask);
+
+	struct cil_nodecon *bnodecon;
+	cil_nodecon_init(&bnodecon);
+	cil_ipaddr_init(&bnodecon->addr);
+	cil_ipaddr_init(&bnodecon->mask);
+
+	anodecon->addr->ip.v6.s6_addr[0] = '5';
+	anodecon->mask->ip.v6.s6_addr[0] = '1';
+	anodecon->addr->family = AF_INET6;
+	
+	bnodecon->addr->ip.v6.s6_addr[0] = '5';
+	bnodecon->mask->ip.v6.s6_addr[0] = '6';
+	bnodecon->addr->family = AF_INET6;
+	
+	int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+	CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_type_a_greater_b(CuTest *tc) {
+	struct cil_fsuse *afsuse;
+	cil_fsuse_init(&afsuse);
+	afsuse->type = CIL_FSUSE_XATTR;
+
+	struct cil_fsuse *bfsuse;
+	cil_fsuse_init(&bfsuse);
+	bfsuse->type = CIL_FSUSE_TASK;
+	
+	int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+	CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_fsuse_compare_type_b_greater_a(CuTest *tc) {
+	struct cil_fsuse *afsuse;
+	cil_fsuse_init(&afsuse);
+	afsuse->type = CIL_FSUSE_TASK;
+
+	struct cil_fsuse *bfsuse;
+	cil_fsuse_init(&bfsuse);
+	bfsuse->type = CIL_FSUSE_XATTR;
+	
+	int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+	CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_fsstr_a_greater_b(CuTest *tc) {
+	struct cil_fsuse *afsuse;
+	cil_fsuse_init(&afsuse);
+	afsuse->type = CIL_FSUSE_XATTR;
+	afsuse->fs_str = "aaa";
+
+	struct cil_fsuse *bfsuse;
+	cil_fsuse_init(&bfsuse);
+	bfsuse->type = CIL_FSUSE_XATTR;
+	bfsuse->fs_str = "bbb";
+	
+	int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+	CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_fsuse_compare_fsstr_b_greater_a(CuTest *tc) {
+	struct cil_fsuse *afsuse;
+	cil_fsuse_init(&afsuse);
+	afsuse->type = CIL_FSUSE_XATTR;
+	afsuse->fs_str = "bbb";
+
+	struct cil_fsuse *bfsuse;
+	cil_fsuse_init(&bfsuse);
+	bfsuse->type = CIL_FSUSE_XATTR;
+	bfsuse->fs_str = "aaa";
+	
+	int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+	CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_equal(CuTest *tc) {
+	struct cil_fsuse *afsuse;
+	cil_fsuse_init(&afsuse);
+	afsuse->type = CIL_FSUSE_XATTR;
+	afsuse->fs_str = "foo";
+
+	struct cil_fsuse *bfsuse;
+	cil_fsuse_init(&bfsuse);
+	bfsuse->type = CIL_FSUSE_XATTR;
+	bfsuse->fs_str = "foo";
+	
+	int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+	CuAssertTrue(tc, rc == 0);
+}
+
+
+
diff --git a/libsepol/cil/test/unit/test_cil_post.h b/libsepol/cil/test/unit/test_cil_post.h
new file mode 100644
index 0000000..b3c16a3
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_post.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_POLICY_H_
+#define TEST_CIL_POLICY_H_
+
+#include "CuTest.h"
+
+void test_cil_post_filecon_compare_meta_a_not_b(CuTest *tc);
+void test_cil_post_filecon_compare_meta_b_not_a(CuTest *tc);
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b(CuTest *tc);
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a(CuTest *tc);
+void test_cil_post_filecon_compare_type_atype_greater_btype(CuTest *tc);
+void test_cil_post_filecon_compare_type_btype_greater_atype(CuTest *tc);
+void test_cil_post_filecon_compare_stemlen_a_greater_b(CuTest *tc);
+void test_cil_post_filecon_compare_stemlen_b_greater_a(CuTest *tc);
+void test_cil_post_filecon_compare_equal(CuTest *tc);
+
+void test_cil_post_portcon_compare_atotal_greater_btotal(CuTest *tc);
+void test_cil_post_portcon_compare_btotal_greater_atotal(CuTest *tc);
+void test_cil_post_portcon_compare_aportlow_greater_bportlow(CuTest *tc);
+void test_cil_post_portcon_compare_bportlow_greater_aportlow(CuTest *tc);
+void test_cil_post_portcon_compare_equal(CuTest *tc);
+
+void test_cil_post_genfscon_compare_atypestr_greater_btypestr(CuTest *tc);
+void test_cil_post_genfscon_compare_btypestr_greater_atypestr(CuTest *tc);
+void test_cil_post_genfscon_compare_apathstr_greater_bpathstr(CuTest *tc);
+void test_cil_post_genfscon_compare_bpathstr_greater_apathstr(CuTest *tc);
+void test_cil_post_genfscon_compare_equal(CuTest *tc);
+
+void test_cil_post_netifcon_compare_a_greater_b(CuTest *tc);
+void test_cil_post_netifcon_compare_b_greater_a(CuTest *tc);
+void test_cil_post_netifcon_compare_equal(CuTest *tc);
+
+void test_cil_post_nodecon_compare_aipv4_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv4_lessthan_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_lessthan_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6(CuTest *tc);
+
+void test_cil_post_fsuse_compare_type_a_greater_b(CuTest *tc);
+void test_cil_post_fsuse_compare_type_b_greater_a(CuTest *tc);
+void test_cil_post_fsuse_compare_fsstr_a_greater_b(CuTest *tc);
+void test_cil_post_fsuse_compare_fsstr_b_greater_a(CuTest *tc);
+void test_cil_post_fsuse_compare_equal(CuTest *tc);
+
+#endif
+
diff --git a/libsepol/cil/test/unit/test_cil_resolve_ast.c b/libsepol/cil/test/unit/test_cil_resolve_ast.c
new file mode 100644
index 0000000..1540c2b
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_resolve_ast.c
@@ -0,0 +1,11319 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_build_ast.h"
+#include "../../src/cil_resolve_ast.h"
+#include "../../src/cil_verify.h"
+#include "../../src/cil_internal.h"
+
+/* this all needs to be moved to a private header file */
+int __cil_resolve_ast_node_helper(struct cil_tree_node *, uint32_t *, void *);
+int __cil_disable_children_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *);
+
+struct cil_args_resolve {
+	struct cil_db *db;
+	enum cil_pass pass;
+	uint32_t *changed;
+	struct cil_tree_node *callstack;
+	struct cil_tree_node *optstack;
+	struct cil_tree_node *macro;
+};
+
+struct cil_args_resolve *gen_resolve_args(struct cil_db *db, enum cil_pass pass, uint32_t *changed, struct cil_tree_node *calls, struct cil_tree_node *opts, struct cil_tree_node *macro)
+{
+	struct cil_args_resolve *args = cil_malloc(sizeof(*args));
+	args->db = db;
+	args->pass = pass;
+	args->changed = changed;
+	args->callstack = calls;
+	args->optstack = opts;
+	args->macro = macro;
+
+	return args;
+}
+
+void test_cil_resolve_name(CuTest *tc) {
+	char *line[] = { "(", "block", "foo", 
+				"(", "typealias", "test", "type_t", ")", 
+				"(", "type", "test", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_tree_node *test_curr = test_db->ast->root->cl_head->cl_head;
+	struct cil_typealias *test_alias = (struct cil_typealias*)test_curr->data;
+	struct cil_tree_node *type_node = NULL;
+
+	int rc = cil_resolve_name(test_curr, test_alias->type_str, CIL_SYM_TYPES, args, &type_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_invalid_type_neg(CuTest *tc) {
+	char *line[] = { "(", "block", "foo", 
+				"(", "typealias", "foo.test2", "type_t", ")", 
+				"(", "type", "test", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_tree_node *test_curr = test_db->ast->root->cl_head->cl_head;
+	struct cil_typealias *test_alias = (struct cil_typealias*)test_curr->data;
+	struct cil_tree_node *type_node = NULL;
+
+	int rc = cil_resolve_name(test_curr, test_alias->type_str, CIL_SYM_TYPES, args, &type_node);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_curr_null_neg(CuTest *tc) {
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	test_db->ast->root = NULL;
+
+	int rc = cil_resolve_ast(test_db, test_db->ast->root);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+/*
+	cil_resolve test cases
+*/
+
+void test_cil_resolve_roleallow(CuTest *tc) {
+	char *line[] = {"(", "role", "foo", ")", \
+			"(", "role", "bar", ")", \
+			"(", "roleallow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roleallow_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "bar", ")", \
+			"(", "roleallow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc1=cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	rc1 = rc1;
+
+	int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roleallow_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo", ")", \
+			"(", "roleallow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+			"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "(", "file", "(", "open", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classmapping_anon_inmacro(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL); 
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	args->pass = CIL_PASS_CALL1;
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next;
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_classmapping_anon_inmacro_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "(", "DNE", "(", "open", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL); 
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	args->pass = CIL_PASS_CALL1;
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next;
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_classmapping_named(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+			"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classmapping_named_classmapname_neg(CuTest *tc) {
+	char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+			"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon_classmapname_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+			"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "dne", "read", "(", "file", "(", "open", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon_permset_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+			"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "(", "dne", "(", "open", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rolebounds(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")", 
+			"(", "role", "role2", ")", 
+			"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rolebounds_exists_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")", 
+			"(", "role", "role2", ")", 
+			"(", "rolebounds", "role1", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+	int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_rolebounds_role1_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")", 
+			"(", "role", "role2", ")", 
+			"(", "rolebounds", "role_DNE", "role2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rolebounds_role2_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")", 
+			"(", "role", "role2", ")", 
+			"(", "rolebounds", "role1", "role_DNE", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_sensalias(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sensalias_sensdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_sensalias(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catalias(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_catalias(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catalias_catdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_catalias(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);	
+}
+
+void test_cil_resolve_catorder(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "category", "c3", ")",
+			"(", "categoryorder", "(", "c0", "c3", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	int rc2 = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_catorder_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "category", "c3", ")",
+			"(", "categoryorder", "(", "c5", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_dominance(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", 
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s0", "s1", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+	int rc2 = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_dominance_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", 
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s6", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_cat_list(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_list *test_cat_list;
+	cil_list_init(&test_cat_list);
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_cat_list_catlistnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_list *test_cat_list;
+	cil_list_init(&test_cat_list);
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+	test_catset->cat_list_str = NULL;
+
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_rescatlistnull_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_list *test_cat_list = NULL;
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_catrange(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+			"(", "categoryset", "somecats", "(", "c0", "(", "c1", "c2", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	struct cil_list *test_cat_list;
+	cil_list_init(&test_cat_list);
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_cat_list_catrange_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+			"(", "categoryset", "somecats", "(", "c0", "(", "c2", "c1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_list *test_cat_list;
+	cil_list_init(&test_cat_list);
+
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MLS;
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_catname_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c5", ")",
+			"(", "category", "c6", ")",
+			"(", "category", "c7", ")",
+			"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+			"(", "categoryset", "somecats", "(", "c0", "(", "c1", "c2", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MLS;
+	struct cil_list *test_cat_list;
+	cil_list_init(&test_cat_list);
+
+	struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+	
+	int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catset(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+	
+	int rc = cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, test_catset, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catset_catlist_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "c4", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+	
+	int rc = cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, test_catset, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catrange(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catrange_catloworder_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	test_db->catorder->head = test_db->catorder->head->next;
+	test_db->catorder->head->next = NULL;
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_catrange_cathighorder_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c255", "c0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_catrange_cat1_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c12", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catrange_cat2_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c0", "c23", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_catrange_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "category", "c500", ")",
+                        "(", "categoryorder", "(", "c0", "c255", "c500", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "(", "c255", "c5", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_senscat_catsetname(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "category", "c500", ")",
+			"(", "categoryset", "foo", "(", "c0", "c255", "c500", ")", ")",
+                        "(", "categoryorder", "(", "c0", "c255", "c500", ")", ")",
+                        "(", "sensitivitycategory", "s1", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+	cil_resolve_catset(test_db->ast->root->cl_head->next->next->next->next->next, test_catset, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_catsetname_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "category", "c500", ")",
+                        "(", "sensitivitycategory", "s1", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_sublist(CuTest *tc) {
+      char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c1", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c1", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "(", "c1", "c255", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_missingsens_neg(CuTest *tc) {
+      char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_category_neg(CuTest *tc) {
+      char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c5", "c255", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_currrangecat(CuTest *tc) {
+      char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c1", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c1", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "(", "c1", "c255", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MISC2;
+
+	int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+	
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_level_catlist(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "categoryorder", "(", "c0", "c1", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", "c1", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", "c1", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", "c1", ")", ")", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next, args);
+	
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level_catset(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "cats", "(", "c0", "c1", "c2", ")", ")",	
+			"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "cats", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "cats", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "cats", ")", ")", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	struct cil_catset *cs = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MLS;
+
+	cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, cs, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level_catset_name_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "cats", "(", "c0", "c1", "c2", ")", ")",	
+			"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "cats", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "dne", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_level_sens_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s1", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s1", "(", "c0", ")", ")", ")",
+			"(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc2);
+}
+
+void test_cil_resolve_level_cat_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+	args->pass = CIL_PASS_MISC3;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc2);
+}
+
+void test_cil_resolve_level_senscat_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s1", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+	args->pass = CIL_PASS_MISC3;
+	int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+	int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc2);
+}
+
+void test_cil_resolve_levelrange_namedlvl(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_levelrange_namedlvl_low_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "range", "(", "DNE", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+	
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_namedlvl_high_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "range", "(", "low", "DNE", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+	
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+	
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl_low_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "DNE", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+	
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl_high_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "dne", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+	
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_constrain_class_neg(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "foo", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain_perm_neg(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain_perm_resolve_neg(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "file", "(", "foo", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_context_macro(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+				"(", "context", "con",
+					"(", "system_u", "object_r", "netif_t", "range", ")", ")", ")", 
+			"(", "call", "mm", "(", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+	
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head->data;
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, test_context,  args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_context_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+				"(", "context", "con",
+					"(", "system_u", "object_r", "netif_t", "range", ")", ")", ")", 
+			"(", "call", "mm", "(", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "DNE", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head->data;
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_context_namedrange(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "range", "(", "low", "high", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "range", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_context_namedrange_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "range", "(", "low", "high", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "DNE", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_user_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_role_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_type_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_anon_level_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "DNE", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data;
+
+	int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, test_context, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "type", "bar_t", ")",
+			"(", "role", "foobar_r", ")",
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roletransition_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "bar_t", ")",
+			"(", "role", "foobar_r", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "role", "foobar_r", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition_resultdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "type", "bar_t", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_type_in_multiple_attrs(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "typeattribute", "attrs2", ")",
+			"(", "type", "type_t", ")",
+			"(", "typeattributeset", "attrs2", "type_t", ")",
+			"(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next->next, args);
+	int rc2 = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_typeattributeset_multiple_excludes_with_not(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "typeattribute", "attrs2", ")",
+			"(", "type", "type_t", ")",
+			"(", "type", "type_b", ")",
+			"(", "type", "type_a", ")",
+			"(", "typeattributeset", "attrs", "(", "and", "type_a", "type_b", ")", ")", 
+			"(", "typeattributeset", "attrs2", "(", "not", "attrs", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_multiple_types_with_and(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "type", "type_t", ")",
+			"(", "type", "type_tt", ")",
+			"(", "typeattributeset", "attrs", "(", "and", "type_t", "type_tt", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_using_attr(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "typeattribute", "attr_a", ")",
+			"(", "typeattributeset", "attrs", "attr_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_name_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_t", ")",
+			"(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_undef_type_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_not(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "type", "type_t", ")",
+			"(", "type", "t_t", ")",
+			"(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_undef_type_not_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "type", "type_t", ")",
+			"(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typealias(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", 
+				"(", "typealias", ".foo.test", "type_t", ")", 
+				"(", "type", "test", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typealias(test_db->ast->root->cl_head->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typealias_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", 
+				"(", "typealias", ".foo", "apache_alias", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typealias(test_db->ast->root->cl_head->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typebounds(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typebounds_repeatbind_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next, args);
+	int rc2 = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc2);
+}
+
+void test_cil_resolve_typebounds_type1_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typebounds_type2_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typepermissive(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typepermissive(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typepermissive_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "typepermissive", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_typepermissive(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nametypetransition_src_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "wrong", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_tgt_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "wrong", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_class_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "bar", "wrong", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+ 
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_dest_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "bar", "file", "wrong", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_namedrange_anon(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "l", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "l", ")", ")",
+			"(", "call", "mm", "(", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_namedrange_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "l", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "l", ")", ")",
+			"(", "call", "mm", "(", "(", "DNE", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->cl_head,  args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_namedrange(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "foo_range", "(", "low", "high", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "foo_range", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_namedrange_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "levelrange", "foo_range", "(", "low", "high", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "DNE", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_type1_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_DNE", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_type2_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_DNE", "class_", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_class_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_DNE", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_call_level_l_anon(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "(", "l", "high", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_l_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "(", "l", "high", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c4", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_h_anon(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "h", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "h", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_h_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "h", ")", ")",
+				"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "h", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c4", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_level_l_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low_DNE", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_level_h_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high_DNE", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_l(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "(", "s0", "(", "c0", ")", ")", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_l_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "(", "s0", "(", "c_DNE", ")", ")", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_h(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "(", "s0", "(", "c0", ")",  ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_h_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "(", "s_DNE", "(", "c0", ")",  ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classcommon(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+			"(", "common", "file", "(", "write", ")", ")",	
+			"(", "classcommon", "file", "file", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classcommon_no_class_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "classcommon", "foo", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classcommon_no_common_neg(CuTest *tc) {
+	char *line[] = {"(", "common", "foo", "(", "read", ")", ")",
+			"(", "classcommon", "foo", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classpermset_named(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "char", "(", "read", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+			"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_named_namedpermlist(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "char", "(", "read", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "char", "baz", ")", ")",
+			"(", "permissionset", "baz", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_named_permlist_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "char", "(", "read", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "dne", "(", "read", ")", ")", ")",
+			"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classpermset_named_unnamedcps_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "char", "(", "read", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+			"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps;
+	cil_classpermset_init(&cps);
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_classpermset_anon(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "(", "char", "(", "read", ")", ")", ")", 
+			"(", "class", "char", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_anon_namedpermlist(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "(", "char", "baz", ")", ")",
+			"(", "permissionset", "baz", "(", "read", ")", ")",
+			"(", "class", "char", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_anon_permlist_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "classmapping", "files", "read", "(", "char", "(", "dne", ")", ")", ")", 
+			"(", "class", "char", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+	int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_avrule_permset(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")",
+			"(", "permissionset", "baz", "(", "open", "write", ")", ")",
+	                "(", "allow", "test", "foo", "(", "bar", "baz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_avrule_permset_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")",
+			"(", "permissionset", "baz", "(", "open", "close", ")", ")",
+	                "(", "allow", "test", "foo", "(", "bar", "dne", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_permset_permdne_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")",
+			"(", "permissionset", "baz", "(", "open", "dne", ")", ")",
+	                "(", "allow", "test", "foo", "(", "bar", "baz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_firsttype_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "fail1", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_secondtype_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "test", "fail2", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_class_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "test", "foo", "(", "fail3", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_perm_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "test", "foo", "(", "bar", "(", "execute", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_transition_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_objdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_resultdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_change_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_objdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_resultdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_member_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_objdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "type", "foobar", ")", 
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_resultdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_filecon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_filecon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "conn", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_filecon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_filecon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_portcon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "portcon", "udp", "25", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_portcon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "portcon", "udp", "25", "conn", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_portcon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "portcon", "udp", "25", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_portcon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "portcon", "udp", "25", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_genfscon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "genfscon", "type", "path", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_genfscon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "genfscon", "type", "path", "conn", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_genfscon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "genfscon", "type", "path", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_genfscon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "genfscon", "type", "path", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_ipv4(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "netmask", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_ipv6(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+			"(", "ipaddr", "netmask", "2001:0DB8:AC10:FE01::", ")",
+			"(", "nodecon", "ip", "netmask", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonipaddr_ipv4(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "(", "192.168.1.1", ")", "netmask", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonnetmask_ipv4(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "(", "192.168.1.1", ")", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonipaddr_ipv6(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "netmask", "2001:0DB8:AC10:FE01::", ")",
+			"(", "nodecon", "(", "2001:0DB8:AC10:FE01::", ")", "netmask", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonnetmask_ipv6(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+			"(", "nodecon", "ip", "(", "2001:0DB8:AC10:FE01::", ")", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_diffipfam_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+			"(", "nodecon", "ip", "(", "192.168.1.1", ")", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_nodecon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "n", "netmask", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_ipaddr_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "n", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_netmask_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "ip", "conn", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "ip", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "ip", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon(CuTest *tc) {
+	char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", 
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_netifcon_otf_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_interface_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", 
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")", 
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "netifcon", "eth1",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed_packet_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")", 
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "netifcon", "eth1",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed_otf_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")", 
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "netifcon", "eth1",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", 
+                        "(", "system_u", "foo_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_sublist_secondlist_missing_neg(CuTest *tc) {
+	char *line[] = {"(", "netifcon", "eth1",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_netifcon(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pirqcon", "1", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pirqcon", "1", "dne", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pirqcon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "etc_t", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "pirqcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "pirqcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_iomemcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "iomemcon", "1", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_iomemcon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "iomemcon", "1", "dne", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_iomemcon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "etc_t", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "iomemcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_iomemcon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "iomemcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ioportcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "ioportcon", "1", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ioportcon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "ioportcon", "1", "dne", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ioportcon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "etc_t", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "ioportcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ioportcon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "ioportcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pcidevicecon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pcidevicecon", "1", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pcidevicecon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pcidevicecon", "1", "dne", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pcidevicecon_anon_context(CuTest *tc) {
+	char *line[] = {"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "etc_t", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "pcidevicecon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pcidevicecon_anon_context_neg(CuTest *tc) {
+	char *line[] = {"(", "pcidevicecon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_fsuse(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+			"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_fsuse_nocontext_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+			"(", "fsuse", "xattr", "ext3", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_fsuse_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+			"(", "fsuse", "xattr", "ext3", "conn", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_fsuse_anon(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "fsuse", "xattr", "ext3", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_fsuse_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "fsuse", "xattr", "ext3", "(", "system_uu", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "sid", "test", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	
+	int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_levels(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "sid", "test", ")",
+			"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+	cil_resolve_level(level, (struct cil_level*)level->data, args);
+	cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+	int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")",
+			"(", "sid", "test", ")",
+			"(", "sidcontext", "test", "con", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_tree_node *context = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+	cil_resolve_context(context, (struct cil_context*)context->data, args);
+
+	int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context_wrongname_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")",
+			"(", "sid", "test", ")",
+			"(", "sidcontext", "test", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	struct cil_tree_node *context = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+	cil_resolve_context(context, (struct cil_context*)context->data, args);
+	
+	int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context_invaliduser_neg(CuTest *tc) {
+           char *line[] = {"(", "category", "c0", ")",
+                        "(", "categoryorder", "(", "c0", ")", ")",
+                        "(", "sensitivity", "s0", ")",
+                        "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+                        "(", "type", "blah_t", ")",
+                        "(", "role", "blah_r", ")",
+                        "(", "user", "blah_u", ")",
+			"(", "sid", "test", ")",
+                        "(", "sidcontext", "test", "(", "", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+        int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_blockinherit(CuTest *tc) {
+	char *line[] = {"(", "block", "baz", "(", "type", "b", ")", ")",
+			"(", "block", "foo", "(", "type", "a", ")", 
+				"(", "blockinherit", "baz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_blockinherit(test_db->ast->root->cl_head->next->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_blockinherit_blockstrdne_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "baz", "(", "type", "b", ")", ")",
+			"(", "block", "foo", "(", "type", "a", ")", 
+				"(", "blockinherit", "dne", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_blockinherit(test_db->ast->root->cl_head->next->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_in_block(CuTest *tc) {
+	char *line[] = {"(", "class", "char", "(", "read", ")", ")",
+			"(", "block", "foo", "(", "type", "a", ")", ")",
+			"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_in_blockstrdne_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "char", "(", "read", ")", ")",
+			"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_in(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_in_macro(CuTest *tc) {
+	char *line[] = {"(", "class", "char", "(", "read", "write", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")", 
+				"(", "allow", "foo", "bar", "(", "file", "(", "write", ")", ")", ")", ")",
+			"(", "in", "mm", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_in_optional(CuTest *tc) {
+	char *line[] = {"(", "class", "char", "(", "read", "write", ")", ")",
+			"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")",
+			"(", "in", "opt", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_noparam(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "qaz", "b", "file", "(", "read", ")", ")", ")",
+			"(", "call", "mm", "(", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_type(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_role(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "role", "a", ")", ")",
+				"(", "role", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "role_r", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_user(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "user", "a", ")", ")",
+				"(", "user", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "user_u", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_sens(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "sens", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")",
+				"(", "sensitivity", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "sens", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_cat(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "category", "a", ")", ")",
+				"(", "category", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "c0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")",
+			"(", "macro", "mm", "(", "(", "categoryset",  "foo", ")", ")",
+				"(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+			"(", "call", "mm", "(", "somecats", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "macro", "mm", "(", "(", "categoryset",  "foo", ")", ")",
+				"(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "c0", "c1", "c2", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "macro", "mm", "(", "(", "categoryset",  "foo", ")", ")",
+				"(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "c5", "(", "c2", ")", "c4", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_level(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_level_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_level_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", "(", "c5", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.0.1", ")",
+			"(", "ipaddr", "ip", "192.168.0.1", ")",
+			"(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+				"(", "nodecon", "addr", "netmask", "con", ")", ")",
+			"(", "call", "mm", "(", "ip", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_ipaddr_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.0.1", ")",
+			"(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+				"(", "nodecon", "addr", "netmask", "con", ")", ")",
+			"(", "call", "mm", "(", "(", "192.168.1.1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_ipaddr_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.0.1", ")",
+			"(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+				"(", "nodecon", "addr", "netmask", "con", ")", ")",
+			"(", "call", "mm", "(", "(", "192.1.1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_class(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classmap(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classmap", "a", ")", ")", 
+				"(", "classmapping", "a", "read", "(", "file", "(", "open", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "read", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_permset(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "open", ")", ")",
+			"(", "type", "dead", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "baz", "(", "close", "read", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")", 
+				"(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_permset_anon(CuTest *tc) {
+	char *line[] = {"(", "type", "dead", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "baz", "(", "close", "read", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")", 
+				"(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "read", "open", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_named(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "file", "(", "open", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "char_w", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_anon(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "(", "file", "(", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknown_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *macro_node = NULL;
+	cil_resolve_name(test_db->ast->root->cl_head->next->next->next, ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str, CIL_SYM_BLOCKS, args, &macro_node);
+	((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro = (struct cil_macro*)macro_node->data;
+	free(((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str);
+	((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str = NULL;
+
+	((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro->params->head->flavor = CIL_NETIFCON;
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknowncall_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "m", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_call1_extraargs_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", "bar", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_copy_dup(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "qaz", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_missing_arg_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "l", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_paramsflavor_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *macro_node = NULL;
+
+	struct cil_call *new_call = ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data);
+	cil_resolve_name(test_db->ast->root->cl_head->next->next->next, new_call->macro_str, CIL_SYM_BLOCKS, args, &macro_node);
+	new_call->macro = (struct cil_macro*)macro_node->data;
+	struct cil_list_item *item = new_call->macro->params->head;
+	item->flavor = CIL_CONTEXT;
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknownflavor_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *macro_node = NULL;
+
+	struct cil_call *new_call = ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data);
+	cil_resolve_name(test_db->ast->root->cl_head->next->next->next, new_call->macro_str, CIL_SYM_BLOCKS, args, &macro_node);
+	new_call->macro = (struct cil_macro*)macro_node->data;
+	struct cil_list_item *item = new_call->macro->params->head;
+	((struct cil_param*)item->data)->flavor = CIL_CONTEXT;
+
+	int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call2_type(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_role(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "role", "a", ")", ")",
+				"(", "role", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "role_r", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_user(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "user", "a", ")", ")",
+				"(", "user", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "user_u", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_sens(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "sens", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")",
+				"(", "sensitivity", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "sens", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_cat(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "category", "a", ")", ")",
+				"(", "category", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "c0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_catset(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")",
+			"(", "macro", "mm", "(", "(", "categoryset",  "foo", ")", ")",
+				"(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+			"(", "call", "mm", "(", "somecats", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_catset_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "macro", "mm", "(", "(", "categoryset",  "foo", ")", ")",
+				"(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "c0", "c1", "c2", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_permset(CuTest *tc) {
+	char *line[] = {"(", "permissionset", "foo", "(", "read", "open", ")", ")",
+			"(", "class", "dead", "(", "close", ")", ")",
+			"(", "class", "bar", "(", "close", ")", ")",
+			"(", "class", "baz", "(", "close", ")", ")",
+			"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")", 
+				"(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_permset_anon(CuTest *tc) {
+	char *line[] = {"(", "class", "dead", "(", "close", ")", ")",
+			"(", "class", "bar", "(", "close", ")", ")",
+			"(", "class", "baz", "(", "close", ")", ")",
+			"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")", 
+				"(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "read", "open", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classpermset_named(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "classpermissionset", "char_w", "(", "file", "(", "open", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "char_w", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classpermset_anon(CuTest *tc) {
+	char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+			"(", "class", "file", "(", "open", ")", ")",
+			"(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")", 
+				"(", "classmapping", "files", "read", "a", ")", ")",
+			"(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_class(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classmap(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+			"(", "classmap", "files", "(", "read", ")", ")",	
+			"(", "macro", "mm", "(", "(", "classmap", "a", ")", ")", 
+				"(", "classmapping", "a", "read", "(", "file", "(", "open", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "files", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_call2_level(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_level_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_ipaddr(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.0.1", ")",
+			"(", "ipaddr", "ip", "192.168.0.1", ")",
+			"(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+				"(", "nodecon", "addr", "netmask", "con", ")", ")",
+			"(", "call", "mm", "(", "ip", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_ipaddr_anon(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+			"(", "ipaddr", "netmask", "192.168.0.1", ")",
+			"(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+				"(", "nodecon", "addr", "netmask", "con", ")", ")",
+			"(", "call", "mm", "(", "(", "192.168.1.1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_unknown_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	((struct cil_args*)((struct cil_list_item *)((struct cil_call *)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data)->args->head)->data)->flavor = CIL_SYM_UNKNOWN;
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call2_name_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+				"(", "class", "b", "(", "read", ")", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "a", CIL_SYM_TYPES, &test_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_call_args_multipleparams(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+				"(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data, "lvl_h", CIL_SYM_LEVELS, &test_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_call_args_diffflavor(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qaz", CIL_LEVEL, &test_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_callnull_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args(NULL, "qaz", CIL_LEVEL, &test_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_namenull_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, NULL, CIL_LEVEL, &test_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_callargsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qas", CIL_LEVEL, &test_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_name_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "baz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node = NULL;
+	//cil_tree_node_init(&test_node);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qas", CIL_TYPE, &test_node);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_expr_stack_bools(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(bif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_tunables(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_type(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "type", "t1", ")",
+			"(", "type", "type_t", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_role(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "role", "r1", ")",
+			"(", "role", "role_r", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "role_r", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_user(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "user", "u1", ")",
+			"(", "user", "user_u", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "user_u", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "beef", "baf", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data; 
+
+	int rc = cil_resolve_expr_stack(bif->expr_stack,test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_expr_stack_emptystr_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data;
+	((struct cil_conditional*)bif->expr_stack->head->data)->str = NULL;
+
+	int rc = cil_resolve_expr_stack(bif->expr_stack,test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_boolif(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = cil_resolve_boolif(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_boolif_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "dne", "N/A", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = cil_resolve_boolif(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_evaluate_expr_stack_and(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_not(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "not", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_or(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "or", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_xor(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "xor", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_eq(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "eq", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_neq(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "neq", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_oper1(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "tunable", "baz", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "jaz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_oper2(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "tunable", "baz", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "baz", "(", "or", "foo", "bar", ")", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "jaz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+	cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next->next, args);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+/*
+void test_cil_evaluate_expr_stack_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "neq", "foo", "bar", ")",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint16_t result = CIL_FALSE;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	struct cil_conditional *new_cond;
+	cil_conditional_init(&new_cond);
+	new_cond->flavor = CIL_COND;
+	char *baz = "baz";
+	new_cond->str = baz;
+	new_cond->flavor = CIL_TUNABLE;
+
+	struct cil_tunableif *tif = test_db->ast->root->cl_head->next->next->next->next->data;
+
+	test_node->data = new_cond;	
+	test_node->cl_head = tif->expr_stack;
+	tif->expr_stack->parent = test_node;
+
+	cil_resolve_expr_stack(test_db, tif->expr_stack, test_db->ast->root->cl_head->next->next->next, NULL);
+	int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+*/
+void test_cil_resolve_tunif_false(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "false",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_tunif_true(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "true", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_tunif_resolveexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "dne", "N/A", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+/*
+void test_cil_resolve_tunif_evaluateexpr_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	struct cil_tree_node *test_node;
+	cil_tree_node_init(&test_node);
+
+	struct cil_conditional *new_cond;
+	cil_conditional_init(&new_cond);
+	new_cond->flavor = CIL_COND;
+	char *baz = "baz";
+	new_cond->str = baz;
+	new_cond->flavor = CIL_TUNABLE;
+
+	struct tunableif *tif = test_db->ast->root->cl_head->next->next->next->data;
+
+	test_node->data = new_cond;	
+	test_node->cl_head = tif->expr_stack;
+	tif->expr_stack->parent = test_node;
+
+	int rc = cil_resolve_tunif(test_db, test_db->ast->root->cl_head->next->next->next, NULL);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+*/
+void test_cil_resolve_userbounds(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")", 
+			"(", "user", "user2", ")", 
+			"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userbounds_exists_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")", 
+			"(", "user", "user2", ")", 
+			"(", "userbounds", "user1", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+	int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_userbounds_user1_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")", 
+			"(", "user", "user2", ")", 
+			"(", "userbounds", "user_DNE", "user2", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userbounds_user2_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")", 
+			"(", "user", "user2", ")", 
+			"(", "userbounds", "user1", "user_DNE", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletype(CuTest *tc) {
+	char *line[] = {"(", "role",  "admin_r", ")",
+			"(", "type", "admin_t", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roletype_type_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "admin_r", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletype_role_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "admin_t", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrole(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrole_user_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrole_role_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userlevel", "foo_u", "low", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userlevel_macro(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+				"(", "userlevel", "foo_u", "l", ")", ")",
+			"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+
+	args->pass = CIL_PASS_CALL1;
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userlevel_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+				"(", "userlevel", "foo_u", "l", ")", ")",
+			"(", "call", "mm", "(", "(", "DNE", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userlevel_level_anon(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "userlevel", "foo_u", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userlevel_level_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "userlevel", "foo_u", "(", "s0", "(", "DNE", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel_user_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userlevel", "DNE", "low", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel_level_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userlevel", "foo_u", "DNE", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "userrange", "foo_u", "range", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrange_macro(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+				"(", "userrange", "foo_u", "range", ")", ")",
+			"(", "call", "mm", "(", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userrange_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+				"(", "userrange", "foo_u", "range", ")", ")",
+			"(", "call", "mm", "(", "(", "DNE", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC2;
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+	args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, SEPOL_OK, rc2);
+	CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userrange_range_anon(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userrange", "foo_u", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrange_range_anon_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userrange", "foo_u", "(", "DNE", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange_user_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "userrange", "DNE", "range", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange_range_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "userrange", "foo_u", "DNE", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_disable_children_helper_optional_enabled(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_optional_disabled(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	uint32_t finished = 0;
+
+	((struct cil_optional *)test_db->ast->root->cl_head->data)->datum.state = CIL_STATE_DISABLED;
+	
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_block(CuTest *tc) {
+	char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_user(CuTest *tc) {
+	char *line[] = {"(", "user", "staff_u", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_role(CuTest *tc) {
+	char *line[] = {"(", "role", "role_r", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_type(CuTest *tc) {
+	char *line[] = {"(", "type", "type_t", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_typealias(CuTest *tc) {
+	char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_common(CuTest *tc) {
+	char *line[] = {"(", "common", "foo", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_class(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_bool(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sens(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_cat(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_catset(CuTest *tc) {
+	char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sid(CuTest *tc) {
+	char *line[] = {"(", "sid", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_macro(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_context(CuTest *tc) {
+	char *line[] = {"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_level(CuTest *tc) {
+	char *line[] = {"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_policycap(CuTest *tc) {
+	char *line[] = {"(", "policycap", "foo", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_perm(CuTest *tc) {
+	char *line[] = {"(", "class", "foo", "(", "read", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_catalias(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_tunable(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "false", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_unknown(CuTest *tc) {
+	char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	uint32_t finished = 0;
+
+	int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+
+/*
+	__cil_resolve_ast_node_helper test cases
+*/
+
+void test_cil_resolve_ast_node_helper_call1(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call1_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "m", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call2(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call2_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "foo", "extra", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_boolif(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "foo", "bar", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_boolif_neg(CuTest *tc) {
+	char *line[] = {"(", "boolean", "foo", "true", ")",
+			"(", "boolean", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "booleanif", "(", "and", "dne", "N/A", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_tunif(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "foo", "bar", ")",
+			"(", "false",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_tunif_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")",
+			"(", "tunable", "bar", "false", ")",
+			"(", "class", "baz", "(", "read", ")", ")",
+			"(", "tunableif", "(", "and", "dne", "N/A", ")",
+			"(", "true",
+			"(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE; 
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catorder(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryorder", "(", "c0", "c1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catorder_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryorder", "(", "c8", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_dominance(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", 
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_dominance_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")", 
+			"(", "sensitivity", "s1", ")",
+			"(", "sensitivity", "s2", ")",
+			"(", "dominance", "(", "s0", "s6", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roleallow(CuTest *tc) {
+	char *line[] = {"(", "role", "foo", ")", \
+			"(", "role", "bar", ")", \
+			"(", "roleallow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);	
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roleallow_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo", ")", \
+			"(", "roleallow", "foo", "bar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sensalias(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sensalias_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catalias(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")", 
+			"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catalias_neg(CuTest *tc) {
+	char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catset(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "category", "c2", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catset_catlist_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "category", "c1", ")",
+			"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catrange(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	args->pass = CIL_PASS_MLS;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catrange_neg(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "categoryrange", "range", "(", "c255", "c0", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_level(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "sensitivitycategory", "s0", "(", "c1", ")", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",  NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC2;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_level_neg(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "sensitivitycategory", "s0", "(", "c1", ")", ")",
+			"(", "level", "l2", "(", "s8", "(", "c1", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_levelrange(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "dominance", "(", "s0", ")", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC2;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_levelrange_neg(CuTest *tc) {
+        char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "dominance", "(", "s0", ")", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "DNE", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_constrain(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "role", "r1", ")",
+			"(", "role", "r2", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_constrain_neg(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", ")", ")",
+			"(", "class", "dir", "(", "create", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "role", "r1", ")",
+			"(", "role", "r2", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_mlsconstrain(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+			"(", "class", "dir", "(", "create", "relabelto", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_mlsconstrain_neg(CuTest *tc) {
+        char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+			"(", "class", "dir", "(", "read", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c1", ")",
+			"(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+			"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_context(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_context_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con",
+                        "(", "system_u", "object_r", "netif_t", "DNE", "high", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_tree_walk(test_db->ast->root,  __cil_resolve_ast_node_helper, NULL, NULL, args);
+	__cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+	__cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+	args->pass = CIL_PASS_MLS;
+	cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+	args->pass = CIL_PASS_MISC3;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_senscat(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_senscat_neg(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+                        "(", "sensitivity", "s1", ")",
+                        "(", "dominance", "(", "s0", "s1", ")", ")",
+                        "(", "category", "c0", ")",
+                        "(", "category", "c255", ")",
+                        "(", "categoryorder", "(", "c0", "c255", ")", ")",
+                        "(", "sensitivitycategory", "s5", "foo", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "type", "bar_t", ")",
+			"(", "role", "foobar_r", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "bar_t", ")",
+			"(", "role", "foobar_r", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "role", "foobar_r", ")", 
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "foo_r", ")",
+			"(", "type", "bar_t", ")",
+			"(", "class", "process", "(", "transition", ")", ")",
+			"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typeattributeset(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "type", "type_t", ")",
+			"(", "type", "type_tt", ")",
+			"(", "typeattributeset", "attrs", "(", "type_t", "type_tt", ")", ")", NULL}; 
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg(CuTest *tc) {
+	char *line[] = {"(", "typeattribute", "attrs", ")",
+			"(", "type", "type_t", ")",
+			"(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typealias(CuTest *tc) {
+	char *line[] = {"(", "block", "foo", 
+				"(", "typealias", ".foo.test", "type_t", ")", 
+				"(", "type", "test", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typealias_notype_neg(CuTest *tc) {
+	char *line[] = {"(", "block", "bar", 
+				"(", "typealias", ".bar.test", "type_t", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typebounds(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typebounds_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_b", ")",
+			"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typepermissive(CuTest *tc) {
+	char *line[] = {"(", "type", "type_a", ")",
+			"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typepermissive_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "type_b", ")",
+			"(", "typepermissive", "type_a", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rangetransition(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rangetransition_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+			"(", "type", "type_a", ")",
+			"(", "type", "type_b", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "rangetransition", "type_DNE", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nametypetransition(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nametypetransition_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "nametypetransition", "str", "foo", "bar", "file", "foobarrr", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")", 
+	                "(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+	                "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_src_nores_neg(CuTest *tc) {
+	char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", 
+			"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_class_nores_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "test", ")", 
+			"(", "type", "foo", ")", 
+			"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_datum_null_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+	                "(", "type", "test", ")", "(", "type", "foo", ")",
+	                "(", "allow", "test", "foo", "(", "bar", "(","fake", ")", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_transition(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_transition_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_change(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_change_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_member(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_member_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "foo", ")",
+			"(", "class", "file", "(", "write", ")", ")",
+			"(", "type", "foobar", ")",
+			"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+	
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+	
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_userbounds(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")",
+			"(", "user", "user2", ")",
+			"(", "userbounds", "user1", "user2", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userbounds_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user1", ")",
+			"(", "userbounds", "user1", "user2", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype(CuTest *tc) {
+	char *line[] = {"(", "role",  "admin_r", ")",
+			"(", "type", "admin_t", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype_role_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "admin_t", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype_type_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "admin_r", ")",
+			"(", "roletype", "admin_r", "admin_t", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole_user_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole_role_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userlevel", "foo_u", "low", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "userlevel", "DNE", "low", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrange(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "userrange", "foo_u", "range", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrange_neg(CuTest *tc) {
+	char *line[] = {"(", "user",  "foo_u", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+			"(", "userrange", "DNE", "range", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_filecon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_filecon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "filecon", "root", "path", "file", "foo", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_portcon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "portcon", "udp", "25", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_portcon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "portcon", "udp", "25", "foo", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_genfscon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "genfscon", "type", "path", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_genfscon_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "genfscon", "type", "path", "foo", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "ip", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "ipp", "netmask", "foo", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon_netmask_neg(CuTest *tc) {
+	char *line[] = {"(", "user", "user_u", ")",
+			"(", "role", "role_r", ")",
+			"(", "type", "type_t", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+			"(", "ipaddr", "ip", "192.168.1.1", ")",
+			"(", "ipaddr", "netmask", "192.168.1.1", ")",
+			"(", "nodecon", "ip", "nnetmask", "foo", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_netifcon(CuTest *tc) {
+	char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", 
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_netifcon_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pirqcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pirqcon", "1", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pirqcon_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pirqcon", "1", "dne", ")", NULL};
+        
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_iomemcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "iomemcon", "1", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_iomemcon_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "iomemcon", "1", "dne", ")", NULL};
+        
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_ioportcon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "ioportcon", "1", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_ioportcon_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "ioportcon", "1", "dne", ")", NULL};
+        
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pcidevicecon(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pcidevicecon", "1", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pcidevicecon_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "pcidevicecon", "1", "dne", ")", NULL};
+        
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_fsuse(CuTest *tc) {
+	char *line[] = {"(", "sensitivity", "s0", ")",
+			"(", "category", "c0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "user", "system_u", ")",
+			"(", "role", "object_r", ")",
+			"(", "type", "netif_t", ")",
+			"(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+			"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_fsuse_neg(CuTest *tc) {
+	char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+			"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sidcontext(CuTest *tc) {
+	char *line[] = {"(", "category", "c0", ")",
+			"(", "categoryorder", "(", "c0", ")", ")",
+			"(", "sensitivity", "s0", ")",
+			"(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+			"(", "type", "blah_t", ")",
+			"(", "role", "blah_r", ")",
+			"(", "user", "blah_u", ")",
+			"(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+			"(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sidcontext_neg(CuTest *tc) {
+       	char *line[] = {"(", "category", "c0", ")",
+                        "(", "categoryorder", "(", "c0", ")", ")",
+                        "(", "sensitivity", "s0", ")",
+                        "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+                        "(", "type", "blah_t", ")",
+                        "(", "role", "blah_r", ")",
+                        "(", "user", "blah_u", ")",
+                        "(", "sidcontext", "test", "(", "", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+ 
+        struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_blockinherit(CuTest *tc) {
+	char *line[] = {"(", "block", "baz", "(", "type", "foo", ")", ")",
+			"(", "block", "bar", "(", "type", "a", ")",
+				"(", "blockinherit", "baz", ")", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_BLKIN, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_classcommon(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+			"(", "common", "file", "(", "write", ")", ")",	
+			"(", "classcommon", "file", "file", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_classcommon_neg(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+			"(", "classcommon", "file", "file", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rolebounds(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")",
+			"(", "role", "role2", ")",
+			"(", "rolebounds", "role1", "role2", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_rolebounds_neg(CuTest *tc) {
+	char *line[] = {"(", "role", "role1", ")",
+			"(", "rolebounds", "role1", "role2", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+
+void test_cil_resolve_ast_node_helper_callstack(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_tree_node *test_ast_node_call;
+	cil_tree_node_init(&test_ast_node_call);
+	test_ast_node_call->flavor = CIL_CALL;
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	__cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_call(CuTest *tc) {
+	char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_tree_node *test_ast_node_call;
+	cil_tree_node_init(&test_ast_node_call);
+	test_ast_node_call->flavor = CIL_CALL;
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optional(CuTest *tc) {
+	char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_tree_node *test_ast_node_opt;
+	cil_tree_node_init(&test_ast_node_opt);
+	test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	// set optional to disabled
+	((struct cil_symtab_datum *)test_db->ast->root->cl_head->data)->state = CIL_STATE_DISABLED;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_macro(CuTest *tc) {
+	char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack(CuTest *tc) {
+	char *line[] = {"(", "class", "baz", "(", "read", ")", ")",
+			"(", "type", "foo", ")",
+			"(", "type", "bar", ")",
+			"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_tree_node *test_ast_node_opt;
+	cil_tree_node_init(&test_ast_node_opt);
+	test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	__cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack_tunable_neg(CuTest *tc) {
+	char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node_opt;
+	cil_tree_node_init(&test_ast_node_opt);
+	test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, test_ast_node_opt, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack_macro_neg(CuTest *tc) {
+	char *line[] = {"(", "type", "qaz", ")",
+			"(", "class", "file", "(", "read", ")", ")",
+			"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+				"(", "type", "b", ")",
+				"(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+			"(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+
+	struct cil_tree_node *test_ast_node_opt;
+	cil_tree_node_init(&test_ast_node_opt);
+	test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, test_ast_node_opt, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+	cil_resolve_call1(test_db->ast->root->cl_head->next->next, args);
+
+	args->pass = CIL_PASS_CALL2;
+
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+	CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodenull_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(NULL, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_extraargsnull_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, NULL);
+	CuAssertIntEquals(tc, 0, finished);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_dbflavor_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_pass_neg(CuTest *tc) {
+	char *line[] = {"(", "role",  "staff_r", ")",
+			"(", "user", "staff_u", ")",
+			"(", "userrole", "staff_u", "staff_r", ")", NULL};
+		
+	struct cil_tree *test_tree;
+	gen_test_tree(&test_tree, line);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);
+	
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	uint32_t finished = 0;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+	cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+	
+	int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+	CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optfailedtoresolve(CuTest *tc) {
+	char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+			"(", "classcommon", "file", "file", ")", NULL};
+        
+	struct cil_tree *test_tree;
+        gen_test_tree(&test_tree, line);
+
+        struct cil_db *test_db;
+        cil_db_init(&test_db);
+
+	struct cil_optional *opt;
+	cil_optional_init(&opt);
+
+	struct cil_tree_node *test_ast_node_opt;
+	cil_tree_node_init(&test_ast_node_opt);
+	test_ast_node_opt->flavor = CIL_OPTIONAL;
+	test_ast_node_opt->data = opt;
+
+	uint32_t changed = CIL_FALSE;
+	struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, test_ast_node_opt, NULL);
+
+        uint32_t finished = 0;
+
+        cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+        int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+        CuAssertIntEquals(tc, SEPOL_OK, rc);
+        CuAssertIntEquals(tc, 0, finished);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_resolve_ast.h b/libsepol/cil/test/unit/test_cil_resolve_ast.h
new file mode 100644
index 0000000..394efde
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_resolve_ast.h
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_RESOLVE_AST_H_
+#define TEST_CIL_RESOLVE_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_resolve_name(CuTest *);
+void test_cil_resolve_name_invalid_type_neg(CuTest *);
+
+void test_cil_resolve_ast_curr_null_neg(CuTest *);
+
+
+/*
+	cil_resolve test cases
+*/
+
+void test_cil_resolve_roleallow(CuTest *);
+void test_cil_resolve_roleallow_srcdecl_neg(CuTest *);
+void test_cil_resolve_roleallow_tgtdecl_neg(CuTest *);
+
+void test_cil_resolve_rolebounds(CuTest *tc);
+void test_cil_resolve_rolebounds_exists_neg(CuTest *tc);
+void test_cil_resolve_rolebounds_role1_neg(CuTest *tc);
+void test_cil_resolve_rolebounds_role2_neg(CuTest *tc);
+
+void test_cil_resolve_sensalias(CuTest *);
+void test_cil_resolve_sensalias_sensdecl_neg(CuTest *);
+
+void test_cil_resolve_catalias(CuTest *);
+void test_cil_resolve_catalias_catdecl_neg(CuTest *);
+
+void test_cil_resolve_catorder(CuTest *);
+void test_cil_resolve_catorder_neg(CuTest *);
+
+void test_cil_resolve_dominance(CuTest *);
+void test_cil_resolve_dominance_neg(CuTest *);
+
+void test_cil_resolve_cat_list(CuTest *);
+void test_cil_resolve_cat_list_catlistnull_neg(CuTest *);
+void test_cil_resolve_cat_list_rescatlistnull_neg(CuTest *);
+void test_cil_resolve_cat_list_catrange(CuTest *);
+void test_cil_resolve_cat_list_catrange_neg(CuTest *);
+void test_cil_resolve_cat_list_catname_neg(CuTest *);
+
+void test_cil_resolve_catset(CuTest *);
+void test_cil_resolve_catset_catlist_neg(CuTest *);
+
+void test_cil_resolve_catrange(CuTest *);
+void test_cil_resolve_catrange_catloworder_neg(CuTest *);
+void test_cil_resolve_catrange_cathighorder_neg(CuTest *);
+void test_cil_resolve_catrange_cat1_neg(CuTest *);
+void test_cil_resolve_catrange_cat2_neg(CuTest *);
+
+void test_cil_resolve_senscat(CuTest *);
+void test_cil_resolve_senscat_catrange_neg(CuTest *);
+void test_cil_resolve_senscat_catsetname(CuTest *);
+void test_cil_resolve_senscat_catsetname_neg(CuTest *);
+void test_cil_resolve_senscat_sublist(CuTest *);
+void test_cil_resolve_senscat_missingsens_neg(CuTest *);
+void test_cil_resolve_senscat_sublist_neg(CuTest *);
+void test_cil_resolve_senscat_category_neg(CuTest *);
+void test_cil_resolve_senscat_currrangecat(CuTest *);
+void test_cil_resolve_senscat_currrangecat_neg(CuTest *);
+
+void test_cil_resolve_level(CuTest *);
+void test_cil_resolve_level_catlist(CuTest *);
+void test_cil_resolve_level_catset(CuTest *);
+void test_cil_resolve_level_catset_name_neg(CuTest *);
+void test_cil_resolve_level_sens_neg(CuTest *);
+void test_cil_resolve_level_cat_neg(CuTest *);
+void test_cil_resolve_level_senscat_neg(CuTest *);
+
+void test_cil_resolve_levelrange_namedlvl(CuTest *);
+void test_cil_resolve_levelrange_namedlvl_low_neg(CuTest *);
+void test_cil_resolve_levelrange_namedlvl_high_neg(CuTest *);
+void test_cil_resolve_levelrange_anonlvl(CuTest *);
+void test_cil_resolve_levelrange_anonlvl_low_neg(CuTest *);
+void test_cil_resolve_levelrange_anonlvl_high_neg(CuTest *);
+
+void test_cil_resolve_constrain(CuTest *);
+void test_cil_resolve_constrain_class_neg(CuTest *);
+void test_cil_resolve_constrain_perm_neg(CuTest *);
+void test_cil_resolve_constrain_perm_resolve_neg(CuTest *);
+
+void test_cil_resolve_context(CuTest *);
+void test_cil_resolve_context_macro(CuTest *);
+void test_cil_resolve_context_macro_neg(CuTest *);
+void test_cil_resolve_context_namedrange(CuTest *);
+void test_cil_resolve_context_namedrange_neg(CuTest *);
+void test_cil_resolve_context_macro_namedrange_anon(CuTest *);
+void test_cil_resolve_context_user_neg(CuTest *);
+void test_cil_resolve_context_role_neg(CuTest *);
+void test_cil_resolve_context_type_neg(CuTest *);
+void test_cil_resolve_context_anon_level_neg(CuTest *);
+
+void test_cil_resolve_roletransition(CuTest *);
+void test_cil_resolve_roletransition_srcdecl_neg(CuTest *);
+void test_cil_resolve_roletransition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_roletransition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_typeattributeset_type_in_multiple_attrs(CuTest *);
+void test_cil_resolve_typeattributeset_multiple_excludes_with_not(CuTest *);
+void test_cil_resolve_typeattributeset_multiple_types_with_and(CuTest *);
+void test_cil_resolve_typeattributeset_using_attr(CuTest *);
+void test_cil_resolve_typeattributeset_name_neg(CuTest *);
+void test_cil_resolve_typeattributeset_undef_type_neg(CuTest *);
+void test_cil_resolve_typeattributeset_not(CuTest *);
+void test_cil_resolve_typeattributeset_undef_type_not_neg(CuTest *);
+
+void test_cil_resolve_typealias(CuTest *);
+void test_cil_resolve_typealias_neg(CuTest *);
+
+void test_cil_resolve_typebounds(CuTest *);
+void test_cil_resolve_typebounds_repeatbind_neg(CuTest *);
+void test_cil_resolve_typebounds_type1_neg(CuTest *);
+void test_cil_resolve_typebounds_type2_neg(CuTest *);
+
+void test_cil_resolve_typepermissive(CuTest *);
+void test_cil_resolve_typepermissive_neg(CuTest *);
+
+void test_cil_resolve_nametypetransition(CuTest *);
+void test_cil_resolve_nametypetransition_src_neg(CuTest *);
+void test_cil_resolve_nametypetransition_tgt_neg(CuTest *);
+void test_cil_resolve_nametypetransition_class_neg(CuTest *);
+void test_cil_resolve_nametypetransition_dest_neg(CuTest *);
+
+void test_cil_resolve_rangetransition(CuTest *);
+void test_cil_resolve_rangetransition_namedrange(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_anon(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_neg(CuTest *);
+void test_cil_resolve_rangetransition_type1_neg(CuTest *);
+void test_cil_resolve_rangetransition_type2_neg(CuTest *);
+void test_cil_resolve_rangetransition_class_neg(CuTest *);
+void test_cil_resolve_rangetransition_call_level_l_anon(CuTest *);
+void test_cil_resolve_rangetransition_call_level_l_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_call_level_h_anon(CuTest *);
+void test_cil_resolve_rangetransition_call_level_h_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_level_l_neg(CuTest *);
+void test_cil_resolve_rangetransition_level_h_neg(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_l(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_l_neg(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_h(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_h_neg(CuTest *);
+
+void test_cil_resolve_classcommon(CuTest *);
+void test_cil_resolve_classcommon_no_class_neg(CuTest *);
+void test_cil_resolve_classcommon_neg(CuTest *);
+void test_cil_resolve_classcommon_no_common_neg(CuTest *);
+
+void test_cil_resolve_classmapping_named(CuTest *);
+void test_cil_resolve_classmapping_anon(CuTest *);
+void test_cil_resolve_classmapping_anon_inmacro(CuTest *);
+void test_cil_resolve_classmapping_anon_inmacro_neg(CuTest *);
+void test_cil_resolve_classmapping_named_classmapname_neg(CuTest *);
+void test_cil_resolve_classmapping_anon_classmapname_neg(CuTest *);
+void test_cil_resolve_classmapping_anon_permset_neg(CuTest *);
+
+void test_cil_resolve_classpermset_named(CuTest *);
+void test_cil_resolve_classpermset_named_namedpermlist(CuTest *);
+void test_cil_resolve_classpermset_named_permlist_neg(CuTest *);
+void test_cil_resolve_classpermset_named_unnamedcps_neg(CuTest *);
+void test_cil_resolve_classpermset_anon(CuTest *);
+void test_cil_resolve_classpermset_anon_namedpermlist(CuTest *);
+void test_cil_resolve_classpermset_anon_permlist_neg(CuTest *);
+
+void test_cil_resolve_avrule(CuTest *);
+void test_cil_resolve_avrule_permset(CuTest *);
+void test_cil_resolve_avrule_permset_neg(CuTest *);
+void test_cil_resolve_avrule_permset_permdne_neg(CuTest *);
+void test_cil_resolve_avrule_firsttype_neg(CuTest *);
+void test_cil_resolve_avrule_secondtype_neg(CuTest *);
+void test_cil_resolve_avrule_class_neg(CuTest *);
+void test_cil_resolve_avrule_perm_neg(CuTest *);
+
+void test_cil_resolve_type_rule_transition(CuTest *);
+void test_cil_resolve_type_rule_transition_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_type_rule_change(CuTest *);
+void test_cil_resolve_type_rule_change_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_type_rule_member(CuTest *);
+void test_cil_resolve_type_rule_member_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_filecon(CuTest *);
+void test_cil_resolve_filecon_neg(CuTest *);
+void test_cil_resolve_filecon_anon_context(CuTest *);
+void test_cil_resolve_filecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_filecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_filecon_neg(CuTest *tc);
+
+void test_cil_resolve_portcon(CuTest *);
+void test_cil_resolve_portcon_neg(CuTest *);
+void test_cil_resolve_portcon_anon_context(CuTest *);
+void test_cil_resolve_portcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_portcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_portcon_neg(CuTest *tc);
+
+void test_cil_resolve_genfscon(CuTest *);
+void test_cil_resolve_genfscon_neg(CuTest *);
+void test_cil_resolve_genfscon_anon_context(CuTest *);
+void test_cil_resolve_genfscon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_genfscon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_genfscon_neg(CuTest *tc);
+
+void test_cil_resolve_nodecon_ipv4(CuTest *);
+void test_cil_resolve_nodecon_ipv6(CuTest *);
+void test_cil_resolve_nodecon_anonipaddr_ipv4(CuTest *);
+void test_cil_resolve_nodecon_anonnetmask_ipv4(CuTest *);
+void test_cil_resolve_nodecon_anonipaddr_ipv6(CuTest *);
+void test_cil_resolve_nodecon_anonnetmask_ipv6(CuTest *);
+void test_cil_resolve_nodecon_diffipfam_neg(CuTest *);
+void test_cil_resolve_nodecon_context_neg(CuTest *);
+void test_cil_resolve_nodecon_ipaddr_neg(CuTest *);
+void test_cil_resolve_nodecon_netmask_neg(CuTest *);
+void test_cil_resolve_nodecon_anon_context(CuTest *);
+void test_cil_resolve_nodecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_nodecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodecon_netmask_neg(CuTest *tc);
+
+void test_cil_resolve_netifcon(CuTest *);
+void test_cil_resolve_netifcon_otf_neg(CuTest *);
+void test_cil_resolve_netifcon_interface_neg(CuTest *);
+void test_cil_resolve_netifcon_unnamed(CuTest *);
+void test_cil_resolve_netifcon_unnamed_packet_neg(CuTest *);
+void test_cil_resolve_netifcon_unnamed_otf_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_netifcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_netifcon_neg(CuTest *tc);
+
+void test_cil_resolve_pirqcon(CuTest *);
+void test_cil_resolve_pirqcon_context_neg(CuTest *);
+void test_cil_resolve_pirqcon_anon_context(CuTest *);
+void test_cil_resolve_pirqcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_pirqcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_pirqcon_neg(CuTest *tc);
+
+void test_cil_resolve_iomemcon(CuTest *);
+void test_cil_resolve_iomemcon_context_neg(CuTest *);
+void test_cil_resolve_iomemcon_anon_context(CuTest *);
+void test_cil_resolve_iomemcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_iomemcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_iomemcon_neg(CuTest *tc);
+
+void test_cil_resolve_ioportcon(CuTest *);
+void test_cil_resolve_ioportcon_context_neg(CuTest *);
+void test_cil_resolve_ioportcon_anon_context(CuTest *);
+void test_cil_resolve_ioportcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_ioportcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_ioportcon_neg(CuTest *tc);
+
+void test_cil_resolve_pcidevicecon(CuTest *);
+void test_cil_resolve_pcidevicecon_context_neg(CuTest *);
+void test_cil_resolve_pcidevicecon_anon_context(CuTest *);
+void test_cil_resolve_pcidevicecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_pcidevicecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_pcidevicecon_neg(CuTest *tc);
+
+void test_cil_resolve_fsuse(CuTest *);
+void test_cil_resolve_fsuse_neg(CuTest *);
+void test_cil_resolve_fsuse_anon(CuTest *);
+void test_cil_resolve_fsuse_anon_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_fsuse(CuTest *tc);
+void test_cil_resolve_ast_node_helper_fsuse_neg(CuTest *tc);
+
+void test_cil_resolve_sidcontext(CuTest *);
+void test_cil_resolve_sidcontext_named_levels(CuTest *);
+void test_cil_resolve_sidcontext_named_context(CuTest *);
+void test_cil_resolve_sidcontext_named_context_wrongname_neg(CuTest *tc);
+void test_cil_resolve_sidcontext_named_context_invaliduser_neg(CuTest *tc);
+void test_cil_resolve_sidcontext_named_context_sidcontextnull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_sidcontext(CuTest *tc);
+void test_cil_resolve_ast_node_helper_sidcontext_neg(CuTest *tc);
+
+void test_cil_resolve_blockinherit(CuTest *);
+void test_cil_resolve_blockinherit_blockstrdne_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_blockinherit(CuTest *tc);
+
+void test_cil_resolve_in_block(CuTest *);
+void test_cil_resolve_in_blockstrdne_neg(CuTest *);
+void test_cil_resolve_in_macro(CuTest *);
+void test_cil_resolve_in_optional(CuTest *);
+
+void test_cil_resolve_call1_noparam(CuTest *);
+void test_cil_resolve_call1_type(CuTest *);
+void test_cil_resolve_call1_role(CuTest *);
+void test_cil_resolve_call1_user(CuTest *);
+void test_cil_resolve_call1_sens(CuTest *);
+void test_cil_resolve_call1_cat(CuTest *);
+void test_cil_resolve_call1_catset(CuTest *);
+void test_cil_resolve_call1_catset_anon(CuTest *);
+void test_cil_resolve_call1_catset_anon_neg(CuTest *);
+void test_cil_resolve_call1_level(CuTest *);
+void test_cil_resolve_call1_class(CuTest *);
+void test_cil_resolve_call1_classmap(CuTest *);
+void test_cil_resolve_call1_permset(CuTest *);
+void test_cil_resolve_call1_permset_anon(CuTest *);
+void test_cil_resolve_call1_classpermset_named(CuTest *);
+void test_cil_resolve_call1_classpermset_anon(CuTest *);
+void test_cil_resolve_call1_classpermset_anon_neg(CuTest *);
+void test_cil_resolve_call1_level(CuTest *);
+void test_cil_resolve_call1_level_anon(CuTest *);
+void test_cil_resolve_call1_level_anon_neg(CuTest *);
+void test_cil_resolve_call1_ipaddr(CuTest *);
+void test_cil_resolve_call1_ipaddr_anon(CuTest *);
+void test_cil_resolve_call1_ipaddr_anon_neg(CuTest *);
+void test_cil_resolve_call1_unknown_neg(CuTest *);
+void test_cil_resolve_call1_unknowncall_neg(CuTest *);
+void test_cil_resolve_call1_extraargs_neg(CuTest *);
+void test_cil_resolve_call1_copy_dup(CuTest *);
+void test_cil_resolve_call1_missing_arg_neg(CuTest *);
+void test_cil_resolve_call1_paramsflavor_neg(CuTest *);
+void test_cil_resolve_call1_unknownflavor_neg(CuTest *);
+
+void test_cil_resolve_call2_type(CuTest *);
+void test_cil_resolve_call2_role(CuTest *);
+void test_cil_resolve_call2_user(CuTest *);
+void test_cil_resolve_call2_sens(CuTest *);
+void test_cil_resolve_call2_cat(CuTest *);
+void test_cil_resolve_call2_catset(CuTest *);
+void test_cil_resolve_call2_catset_anon(CuTest *);
+void test_cil_resolve_call2_permset(CuTest *);
+void test_cil_resolve_call2_permset_anon(CuTest *);
+void test_cil_resolve_call2_classpermset_named(CuTest *);
+void test_cil_resolve_call2_classpermset_anon(CuTest *);
+void test_cil_resolve_call2_class(CuTest *);
+void test_cil_resolve_call2_classmap(CuTest *);
+void test_cil_resolve_call2_level(CuTest *);
+void test_cil_resolve_call2_level_anon(CuTest *);
+void test_cil_resolve_call2_ipaddr(CuTest *);
+void test_cil_resolve_call2_ipaddr_anon(CuTest *);
+void test_cil_resolve_call2_unknown_neg(CuTest *);
+
+void test_cil_resolve_name_call_args(CuTest *);
+void test_cil_resolve_name_call_args_multipleparams(CuTest *);
+void test_cil_resolve_name_call_args_diffflavor(CuTest *);
+void test_cil_resolve_name_call_args_callnull_neg(CuTest *);
+void test_cil_resolve_name_call_args_namenull_neg(CuTest *);
+void test_cil_resolve_name_call_args_callargsnull_neg(CuTest *);
+void test_cil_resolve_name_call_args_name_neg(CuTest *);
+
+void test_cil_resolve_expr_stack_bools(CuTest *);
+void test_cil_resolve_expr_stack_tunables(CuTest *);
+void test_cil_resolve_expr_stack_type(CuTest *);
+void test_cil_resolve_expr_stack_role(CuTest *);
+void test_cil_resolve_expr_stack_user(CuTest *);
+void test_cil_resolve_expr_stack_neg(CuTest *);
+void test_cil_resolve_expr_stack_emptystr_neg(CuTest *);
+
+void test_cil_resolve_boolif(CuTest *);
+void test_cil_resolve_boolif_neg(CuTest *);
+
+void test_cil_evaluate_expr_stack_and(CuTest *);
+void test_cil_evaluate_expr_stack_not(CuTest *);
+void test_cil_evaluate_expr_stack_or(CuTest *);
+void test_cil_evaluate_expr_stack_xor(CuTest *);
+void test_cil_evaluate_expr_stack_eq(CuTest *);
+void test_cil_evaluate_expr_stack_neq(CuTest *);
+void test_cil_evaluate_expr_stack_oper1(CuTest *);
+void test_cil_evaluate_expr_stack_oper2(CuTest *);
+void test_cil_evaluate_expr_stack_neg(CuTest *);
+
+void test_cil_resolve_tunif_false(CuTest *);
+void test_cil_resolve_tunif_true(CuTest *);
+void test_cil_resolve_tunif_resolveexpr_neg(CuTest *);
+void test_cil_resolve_tunif_evaluateexpr_neg(CuTest *);
+
+void test_cil_resolve_userbounds(CuTest *tc);
+void test_cil_resolve_userbounds_exists_neg(CuTest *tc);
+void test_cil_resolve_userbounds_user1_neg(CuTest *tc);
+void test_cil_resolve_userbounds_user2_neg(CuTest *tc);
+
+void test_cil_resolve_roletype(CuTest *tc);
+void test_cil_resolve_roletype_type_neg(CuTest *tc);
+void test_cil_resolve_roletype_role_neg(CuTest *tc);
+
+void test_cil_resolve_userrole(CuTest *tc);
+void test_cil_resolve_userrole_user_neg(CuTest *tc);
+void test_cil_resolve_userrole_role_neg(CuTest *tc);
+
+void test_cil_resolve_userlevel(CuTest *tc);
+void test_cil_resolve_userlevel_macro(CuTest *tc);
+void test_cil_resolve_userlevel_macro_neg(CuTest *tc);
+void test_cil_resolve_userlevel_level_anon(CuTest *tc);
+void test_cil_resolve_userlevel_level_anon_neg(CuTest *tc);
+void test_cil_resolve_userlevel_user_neg(CuTest *tc);
+void test_cil_resolve_userlevel_level_neg(CuTest *tc);
+
+void test_cil_resolve_userrange(CuTest *tc);
+void test_cil_resolve_userrange_macro(CuTest *tc);
+void test_cil_resolve_userrange_macro_neg(CuTest *tc);
+void test_cil_resolve_userrange_range_anon(CuTest *tc);
+void test_cil_resolve_userrange_range_anon_neg(CuTest *tc);
+void test_cil_resolve_userrange_user_neg(CuTest *tc);
+void test_cil_resolve_userrange_range_neg(CuTest *tc);
+
+void test_cil_disable_children_helper_optional_enabled(CuTest *tc);
+void test_cil_disable_children_helper_optional_disabled(CuTest *tc);
+void test_cil_disable_children_helper_block(CuTest *tc);
+void test_cil_disable_children_helper_user(CuTest *tc);
+void test_cil_disable_children_helper_role(CuTest *tc);
+void test_cil_disable_children_helper_type(CuTest *tc);
+void test_cil_disable_children_helper_typealias(CuTest *tc);
+void test_cil_disable_children_helper_common(CuTest *tc);
+void test_cil_disable_children_helper_class(CuTest *tc);
+void test_cil_disable_children_helper_bool(CuTest *tc);
+void test_cil_disable_children_helper_sens(CuTest *tc);
+void test_cil_disable_children_helper_cat(CuTest *tc);
+void test_cil_disable_children_helper_catset(CuTest *tc);
+void test_cil_disable_children_helper_sid(CuTest *tc);
+void test_cil_disable_children_helper_macro(CuTest *tc);
+void test_cil_disable_children_helper_context(CuTest *tc);
+void test_cil_disable_children_helper_level(CuTest *tc);
+void test_cil_disable_children_helper_policycap(CuTest *tc);
+void test_cil_disable_children_helper_perm(CuTest *tc);
+void test_cil_disable_children_helper_catalias(CuTest *tc);
+void test_cil_disable_children_helper_sensalias(CuTest *tc);
+void test_cil_disable_children_helper_tunable(CuTest *tc);
+void test_cil_disable_children_helper_unknown(CuTest *tc);
+
+/*
+	__cil_resolve_ast_node_helper test cases
+*/
+
+void test_cil_resolve_ast_node_helper_call1(CuTest *);
+void test_cil_resolve_ast_node_helper_call1_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_call2(CuTest *);
+void test_cil_resolve_ast_node_helper_call2_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_boolif(CuTest *);
+void test_cil_resolve_ast_node_helper_boolif_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_tunif(CuTest *);
+void test_cil_resolve_ast_node_helper_tunif_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catorder(CuTest *);
+void test_cil_resolve_ast_node_helper_catorder_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_dominance(CuTest *);
+void test_cil_resolve_ast_node_helper_dominance_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_roleallow(CuTest *);
+void test_cil_resolve_ast_node_helper_roleallow_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_rolebounds(CuTest *tc);
+void test_cil_resolve_ast_node_helper_rolebounds_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_sensalias(CuTest *);
+void test_cil_resolve_ast_node_helper_sensalias_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catalias(CuTest *);
+void test_cil_resolve_ast_node_helper_catalias_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catset(CuTest *);
+void test_cil_resolve_ast_node_helper_catset_catlist_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_level(CuTest *);
+void test_cil_resolve_ast_node_helper_level_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_levelrange(CuTest *);
+void test_cil_resolve_ast_node_helper_levelrange_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_constrain(CuTest *);
+void test_cil_resolve_ast_node_helper_constrain_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_mlsconstrain(CuTest *);
+void test_cil_resolve_ast_node_helper_mlsconstrain_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_context(CuTest *);
+void test_cil_resolve_ast_node_helper_context_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catrange(CuTest *tc);
+void test_cil_resolve_ast_node_helper_catrange_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_senscat(CuTest *tc);
+void test_cil_resolve_ast_node_helper_senscat_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_roletransition(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typeattributeset(CuTest *);
+void test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typealias(CuTest *);
+void test_cil_resolve_ast_node_helper_typealias_notype_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typebounds(CuTest *);
+void test_cil_resolve_ast_node_helper_typebounds_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typepermissive(CuTest *);
+void test_cil_resolve_ast_node_helper_typepermissive_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_nametypetransition(CuTest *);
+void test_cil_resolve_ast_node_helper_nametypetransition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_rangetransition(CuTest *);
+void test_cil_resolve_ast_node_helper_rangetransition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_avrule(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_src_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_class_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_datum_null_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_transition(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_transition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_change(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_change_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_member(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_member_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_userbounds(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userbounds_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_roletype(CuTest *tc);
+void test_cil_resolve_ast_node_helper_roletype_role_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_roletype_type_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userrole(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrole_user_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrole_role_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userrange(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrange_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_classcommon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_classcommon_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_callstack(CuTest *tc);
+void test_cil_resolve_ast_node_helper_call(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optional(CuTest *tc);
+void test_cil_resolve_ast_node_helper_macro(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack_tunable_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack_macro_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodenull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_extraargsnull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optfailedtoresolve(CuTest *tc);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_symtab.c b/libsepol/cil/test/unit/test_cil_symtab.c
new file mode 100644
index 0000000..379149a
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_symtab.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_symtab.h"
+
+#include "../../src/cil_tree.h"
+#include "../../src/cil_symtab.h"
+#include "../../src/cil_internal.h"
+
+void test_cil_symtab_insert(CuTest *tc) {
+	symtab_t *test_symtab = NULL;
+	char* test_name = "test";
+	struct cil_block *test_block = malloc(sizeof(*test_block));
+
+	struct cil_tree_node *test_ast_node;
+	cil_tree_node_init(&test_ast_node);
+
+	struct cil_db *test_db;
+	cil_db_init(&test_db);   
+
+	test_ast_node->parent = test_db->ast->root;
+	test_ast_node->line = 1;
+
+	cil_symtab_array_init(test_block->symtab, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK]);
+
+	test_block->is_abstract = 0;
+
+	cil_get_symtab(test_db, test_ast_node->parent, &test_symtab, CIL_SYM_BLOCKS);
+
+	int rc = cil_symtab_insert(test_symtab, (hashtab_key_t)test_name, (struct cil_symtab_datum*)test_block, test_ast_node);
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_symtab.h b/libsepol/cil/test/unit/test_cil_symtab.h
new file mode 100644
index 0000000..76053af
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_symtab.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_SYMTAB_H_
+#define TEST_CIL_SYMTAB_H_
+
+#include "CuTest.h"
+
+void test_cil_symtab_insert(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_tree.c b/libsepol/cil/test/unit/test_cil_tree.c
new file mode 100644
index 0000000..8bdc113
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_tree.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_tree.h"
+
+#include "../../src/cil_tree.h"
+
+void test_cil_tree_node_init(CuTest *tc) {
+   struct cil_tree_node *test_node;
+
+   cil_tree_node_init(&test_node);
+
+   CuAssertPtrNotNull(tc, test_node);
+   CuAssertPtrEquals(tc, NULL, test_node->cl_head);
+   CuAssertPtrEquals(tc, NULL, test_node->cl_tail);
+   CuAssertPtrEquals(tc, NULL, test_node->parent);
+   CuAssertPtrEquals(tc, NULL, test_node->data);
+   CuAssertPtrEquals(tc, NULL, test_node->next);
+   CuAssertIntEquals(tc, 0, test_node->flavor);
+   CuAssertIntEquals(tc, 0, test_node->line);
+
+   free(test_node);
+}
+
+void test_cil_tree_init(CuTest *tc) {
+	struct cil_tree *test_tree;
+
+	int rc = cil_tree_init(&test_tree);
+
+	CuAssertIntEquals(tc, SEPOL_OK, rc);
+	CuAssertPtrNotNull(tc, test_tree);
+	CuAssertPtrEquals(tc, NULL, test_tree->root->cl_head);
+	CuAssertPtrEquals(tc, NULL, test_tree->root->cl_tail);
+	CuAssertPtrEquals(tc, NULL, test_tree->root->parent);
+	CuAssertPtrEquals(tc, NULL, test_tree->root->data);
+	CuAssertPtrEquals(tc, NULL, test_tree->root->next);
+	CuAssertIntEquals(tc, 0, test_tree->root->flavor);
+	CuAssertIntEquals(tc, 0, test_tree->root->line);
+
+	free(test_tree);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_tree.h b/libsepol/cil/test/unit/test_cil_tree.h
new file mode 100644
index 0000000..15c0824
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_tree.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_TREE_H_
+#define TEST_CIL_TREE_H_
+
+#include "CuTest.h"
+
+void test_cil_tree_node_init(CuTest *);
+void test_cil_tree_init(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_integration.c b/libsepol/cil/test/unit/test_integration.c
new file mode 100644
index 0000000..d9cdb46
--- /dev/null
+++ b/libsepol/cil/test/unit/test_integration.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_integration.h"
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void test_integration(CuTest *tc) {
+	int status = 0, status1 = 0, status2 = 0;
+
+	status = system("./secilc -M -c 24 test/integration.cil &> /dev/null");
+
+	if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGQUIT))
+		printf("Call to system for secilc failed.\n");
+	
+	status1 = system("checkpolicy -M -c 24 -o policy.conf.24 test/policy.conf &> /dev/null");
+
+	if (WIFSIGNALED(status1) && (WTERMSIG(status1) == SIGINT || WTERMSIG(status1) == SIGQUIT))
+		printf("Call to checkpolicy failed.\n");
+	
+	status2 = system("sediff -q policy.24 \\; policy.conf.24 &> /dev/null");
+
+	if (WIFSIGNALED(status2) && (WTERMSIG(status2) == SIGINT || WTERMSIG(status2) == SIGQUIT))
+		printf("Call to sediff for secilc failed.\n");
+	
+	CuAssertIntEquals(tc, 1, WIFEXITED(status));
+	CuAssertIntEquals(tc, 0, WEXITSTATUS(status));
+	CuAssertIntEquals(tc, 1, WIFEXITED(status1));
+	CuAssertIntEquals(tc, 0, WEXITSTATUS(status1));
+	CuAssertIntEquals(tc, 1, WIFEXITED(status2));
+	CuAssertIntEquals(tc, 0, WEXITSTATUS(status2));
+}
+
+void test_min_policy(CuTest *tc) {
+	int status = 0;
+
+	status = system("./secilc -M -c 24 test/policy.cil &> /dev/null");
+
+	if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGQUIT))
+		printf("Call to system for secilc failed.\n");
+	
+	CuAssertIntEquals(tc, 1, WIFEXITED(status));
+	CuAssertIntEquals(tc, 0, WEXITSTATUS(status));
+}
diff --git a/libsepol/cil/test/unit/test_integration.h b/libsepol/cil/test/unit/test_integration.h
new file mode 100644
index 0000000..4cbcce3
--- /dev/null
+++ b/libsepol/cil/test/unit/test_integration.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_INTEGRATION_H
+#define TEST_INTEGRATION_H
+
+#include "CuTest.h"
+
+void test_min_policy(CuTest *);
+void test_integration(CuTest *);
+
+#endif
diff --git a/libsepol/include/Makefile b/libsepol/include/Makefile
new file mode 100644
index 0000000..56b7a11
--- /dev/null
+++ b/libsepol/include/Makefile
@@ -0,0 +1,17 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCDIR ?= $(PREFIX)/include/sepol
+CILDIR ?= ../cil
+
+all:
+
+install: all
+	test -d $(INCDIR) || install -m 755 -d $(INCDIR)
+	test -d $(INCDIR)/policydb || install -m 755 -d $(INCDIR)/policydb
+	test -d $(INCDIR)/cil || install -m 755 -d $(INCDIR)/cil
+	install -m 644 $(wildcard sepol/*.h) $(INCDIR)
+	install -m 644 $(wildcard sepol/policydb/*.h) $(INCDIR)/policydb
+	install -m 644 $(wildcard $(CILDIR)/include/cil/*.h) $(INCDIR)/cil
+
+indent:
+	../../scripts/Lindent $(wildcard sepol/*.h)
diff --git a/libsepol/include/sepol/boolean_record.h b/libsepol/include/sepol/boolean_record.h
new file mode 100644
index 0000000..9af16be
--- /dev/null
+++ b/libsepol/include/sepol/boolean_record.h
@@ -0,0 +1,55 @@
+#ifndef _SEPOL_BOOLEAN_RECORD_H_
+#define _SEPOL_BOOLEAN_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_bool;
+struct sepol_bool_key;
+typedef struct sepol_bool sepol_bool_t;
+typedef struct sepol_bool_key sepol_bool_key_t;
+
+/* Key */
+extern int sepol_bool_key_create(sepol_handle_t * handle,
+				 const char *name, sepol_bool_key_t ** key);
+
+extern void sepol_bool_key_unpack(const sepol_bool_key_t * key,
+				  const char **name);
+
+extern int sepol_bool_key_extract(sepol_handle_t * handle,
+				  const sepol_bool_t * boolean,
+				  sepol_bool_key_t ** key_ptr);
+
+extern void sepol_bool_key_free(sepol_bool_key_t * key);
+
+extern int sepol_bool_compare(const sepol_bool_t * boolean,
+			      const sepol_bool_key_t * key);
+
+extern int sepol_bool_compare2(const sepol_bool_t * boolean,
+			       const sepol_bool_t * boolean2);
+
+/* Name */
+extern const char *sepol_bool_get_name(const sepol_bool_t * boolean);
+
+extern int sepol_bool_set_name(sepol_handle_t * handle,
+			       sepol_bool_t * boolean, const char *name);
+
+/* Value */
+extern int sepol_bool_get_value(const sepol_bool_t * boolean);
+
+extern void sepol_bool_set_value(sepol_bool_t * boolean, int value);
+
+/* Create/Clone/Destroy */
+extern int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr);
+
+extern int sepol_bool_clone(sepol_handle_t * handle,
+			    const sepol_bool_t * boolean,
+			    sepol_bool_t ** bool_ptr);
+
+extern void sepol_bool_free(sepol_bool_t * boolean);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/booleans.h b/libsepol/include/sepol/booleans.h
new file mode 100644
index 0000000..7374dde
--- /dev/null
+++ b/libsepol/include/sepol/booleans.h
@@ -0,0 +1,63 @@
+#ifndef _SEPOL_BOOLEANS_H_
+#define _SEPOL_BOOLEANS_H_
+
+#include <stddef.h>
+#include <sepol/policydb.h>
+#include <sepol/boolean_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*--------------compatibility--------------*/
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+   and a boolean configuration file named by 'boolpath', rewrite the binary
+   policy for the boolean settings in the boolean configuration file.
+   The binary policy is rewritten in place in memory.
+   Returns 0 upon success, or -1 otherwise. */
+extern int sepol_genbools(void *data, size_t len, char *boolpath);
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+   and boolean settings specified by the parallel arrays ('names', 'values')
+   with 'nel' elements, rewrite the binary policy for the boolean settings.
+   The binary policy is rewritten in place in memory.
+   Returns 0 upon success or -1 otherwise. */
+extern int sepol_genbools_array(void *data, size_t len,
+				char **names, int *values, int nel);
+/*---------------end compatbility------------*/
+
+/* Set the specified boolean */
+extern int sepol_bool_set(sepol_handle_t * handle,
+			  sepol_policydb_t * policydb,
+			  const sepol_bool_key_t * key,
+			  const sepol_bool_t * data);
+
+/* Return the number of booleans */
+extern int sepol_bool_count(sepol_handle_t * handle,
+			    const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified boolean exists */
+extern int sepol_bool_exists(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     const sepol_bool_key_t * key, int *response);
+
+/* Query a boolean - returns the boolean, or NULL if not found */
+extern int sepol_bool_query(sepol_handle_t * handle,
+			    const sepol_policydb_t * p,
+			    const sepol_bool_key_t * key,
+			    sepol_bool_t ** response);
+
+/* Iterate the booleans
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_bool_iterate(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      int (*fn) (const sepol_bool_t * boolean,
+					 void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/context.h b/libsepol/include/sepol/context.h
new file mode 100644
index 0000000..a69e8c9
--- /dev/null
+++ b/libsepol/include/sepol/context.h
@@ -0,0 +1,30 @@
+#ifndef _SEPOL_CONTEXT_H_
+#define _SEPOL_CONTEXT_H_
+
+#include <sepol/context_record.h>
+#include <sepol/policydb.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* -- Deprecated -- */
+
+extern int sepol_check_context(const char *context);
+
+/* -- End deprecated -- */
+
+extern int sepol_context_check(sepol_handle_t * handle,
+			       const sepol_policydb_t * policydb,
+			       const sepol_context_t * context);
+
+extern int sepol_mls_contains(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      const char *mls1,
+			      const char *mls2, int *response);
+
+extern int sepol_mls_check(sepol_handle_t * handle,
+			   const sepol_policydb_t * policydb, const char *mls);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/context_record.h b/libsepol/include/sepol/context_record.h
new file mode 100644
index 0000000..c07da8f
--- /dev/null
+++ b/libsepol/include/sepol/context_record.h
@@ -0,0 +1,57 @@
+#ifndef _SEPOL_CONTEXT_RECORD_H_
+#define _SEPOL_CONTEXT_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_context;
+typedef struct sepol_context sepol_context_t;
+
+/* We don't need a key, because the context is never stored
+ * in a data collection by itself */
+
+/* User */
+extern const char *sepol_context_get_user(const sepol_context_t * con);
+
+extern int sepol_context_set_user(sepol_handle_t * handle,
+				  sepol_context_t * con, const char *user);
+
+/* Role */
+extern const char *sepol_context_get_role(const sepol_context_t * con);
+
+extern int sepol_context_set_role(sepol_handle_t * handle,
+				  sepol_context_t * con, const char *role);
+
+/* Type */
+extern const char *sepol_context_get_type(const sepol_context_t * con);
+
+extern int sepol_context_set_type(sepol_handle_t * handle,
+				  sepol_context_t * con, const char *type);
+
+/* MLS */
+extern const char *sepol_context_get_mls(const sepol_context_t * con);
+
+extern int sepol_context_set_mls(sepol_handle_t * handle,
+				 sepol_context_t * con, const char *mls_range);
+
+/* Create/Clone/Destroy */
+extern int sepol_context_create(sepol_handle_t * handle,
+				sepol_context_t ** con_ptr);
+
+extern int sepol_context_clone(sepol_handle_t * handle,
+			       const sepol_context_t * con,
+			       sepol_context_t ** con_ptr);
+
+extern void sepol_context_free(sepol_context_t * con);
+
+/* Parse to/from string */
+extern int sepol_context_from_string(sepol_handle_t * handle,
+				     const char *str, sepol_context_t ** con);
+
+extern int sepol_context_to_string(sepol_handle_t * handle,
+				   const sepol_context_t * con, char **str_ptr);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/debug.h b/libsepol/include/sepol/debug.h
new file mode 100644
index 0000000..b852c8d
--- /dev/null
+++ b/libsepol/include/sepol/debug.h
@@ -0,0 +1,39 @@
+#ifndef _SEPOL_DEBUG_H_
+#define _SEPOL_DEBUG_H_
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Deprecated */
+extern void sepol_debug(int on);
+/* End deprecated */
+
+#define SEPOL_MSG_ERR  1
+#define SEPOL_MSG_WARN 2
+#define SEPOL_MSG_INFO 3
+
+extern int sepol_msg_get_level(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_channel(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_fname(sepol_handle_t * handle);
+
+/* Set the messaging callback. 
+ * By the default, the callback will print
+ * the message on standard output, in a 
+ * particular format. Passing NULL here
+ * indicates that messaging should be suppressed */
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+				   __attribute__ ((format(printf, 3, 4)))
+#endif
+				   void (*msg_callback) (void *varg,
+							 sepol_handle_t *
+							 handle,
+							 const char *fmt, ...),
+				   void *msg_callback_arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/errcodes.h b/libsepol/include/sepol/errcodes.h
new file mode 100644
index 0000000..eba7088
--- /dev/null
+++ b/libsepol/include/sepol/errcodes.h
@@ -0,0 +1,29 @@
+/* Author: Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_errno_h__
+#define __sepol_errno_h__
+
+#include <errno.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define SEPOL_OK             0
+
+/* These first error codes are defined for compatibility with
+ * previous version of libsepol. In the future, custome error
+ * codes that don't map to system error codes should be defined
+ * outside of the range of system error codes.
+ */
+#define SEPOL_ERR            -1
+#define SEPOL_ENOTSUP        -2  /* feature not supported in module language */
+#define SEPOL_EREQ           -3  /* requirements not met */
+
+/* Error codes that map to system error codes */
+#define SEPOL_ENOMEM         -ENOMEM
+#define SEPOL_ERANGE         -ERANGE
+#define SEPOL_EEXIST         -EEXIST
+#define SEPOL_ENOENT         -ENOENT
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/handle.h b/libsepol/include/sepol/handle.h
new file mode 100644
index 0000000..00ed0ed
--- /dev/null
+++ b/libsepol/include/sepol/handle.h
@@ -0,0 +1,39 @@
+#ifndef _SEPOL_HANDLE_H_
+#define _SEPOL_HANDLE_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_handle;
+typedef struct sepol_handle sepol_handle_t;
+
+/* Create and return a sepol handle. */
+sepol_handle_t *sepol_handle_create(void);
+
+/* Get whether or not dontaudits will be disabled, same values as
+ * specified by set_disable_dontaudit. This value reflects the state
+ * your system will be set to upon commit, not necessarily its
+ * current state.*/
+int sepol_get_disable_dontaudit(sepol_handle_t * sh);
+
+/* Set whether or not to disable dontaudits, 0 is default and does 
+ * not disable dontaudits, 1 disables them */
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit);
+
+/* Set whether module_expand() should consume the base policy passed in.
+ * This should reduce the amount of memory required to expand the policy. */
+void sepol_set_expand_consume_base(sepol_handle_t * sh, int consume_base);
+
+/* Destroy a sepol handle. */
+void sepol_handle_destroy(sepol_handle_t *);
+
+/* Get whether or not needless unused branch of tunables would be preserved */
+int sepol_get_preserve_tunables(sepol_handle_t * sh);
+
+/* Set whether or not to preserve the needless unused branch of tunables,
+ * 0 is default and discard such branch, 1 preserves them */
+void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/iface_record.h b/libsepol/include/sepol/iface_record.h
new file mode 100644
index 0000000..81d7027
--- /dev/null
+++ b/libsepol/include/sepol/iface_record.h
@@ -0,0 +1,63 @@
+#ifndef _SEPOL_IFACE_RECORD_H_
+#define _SEPOL_IFACE_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sepol/context_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_iface;
+struct sepol_iface_key;
+typedef struct sepol_iface sepol_iface_t;
+typedef struct sepol_iface_key sepol_iface_key_t;
+
+/* Key */
+extern int sepol_iface_compare(const sepol_iface_t * iface,
+			       const sepol_iface_key_t * key);
+
+extern int sepol_iface_compare2(const sepol_iface_t * iface,
+				const sepol_iface_t * iface2);
+
+extern void sepol_iface_key_unpack(const sepol_iface_key_t * key,
+				   const char **name);
+
+extern int sepol_iface_key_create(sepol_handle_t * handle,
+				  const char *name,
+				  sepol_iface_key_t ** key_ptr);
+
+extern int sepol_iface_key_extract(sepol_handle_t * handle,
+				   const sepol_iface_t * iface,
+				   sepol_iface_key_t ** key_ptr);
+
+extern void sepol_iface_key_free(sepol_iface_key_t * key);
+
+/* Name */
+extern const char *sepol_iface_get_name(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_name(sepol_handle_t * handle,
+				sepol_iface_t * iface, const char *name);
+
+/* Context */
+extern sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_ifcon(sepol_handle_t * handle,
+				 sepol_iface_t * iface, sepol_context_t * con);
+
+extern sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_msgcon(sepol_handle_t * handle,
+				  sepol_iface_t * iface, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_iface_create(sepol_handle_t * handle,
+			      sepol_iface_t ** iface_ptr);
+
+extern int sepol_iface_clone(sepol_handle_t * handle,
+			     const sepol_iface_t * iface,
+			     sepol_iface_t ** iface_ptr);
+
+extern void sepol_iface_free(sepol_iface_t * iface);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/interfaces.h b/libsepol/include/sepol/interfaces.h
new file mode 100644
index 0000000..3cb5043
--- /dev/null
+++ b/libsepol/include/sepol/interfaces.h
@@ -0,0 +1,47 @@
+#ifndef __SEPOL_INTERFACES_H_
+#define __SEPOL_INTERFACES_H_
+
+#include <sepol/policydb.h>
+#include <sepol/iface_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     unsigned int *response);
+
+/* Check if an interface exists */
+extern int sepol_iface_exists(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      const sepol_iface_key_t * key, int *response);
+
+/* Query an interface - returns the interface, 
+ * or NULL if not found */
+extern int sepol_iface_query(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     const sepol_iface_key_t * key,
+			     sepol_iface_t ** response);
+
+/* Modify an interface, or add it, if the key
+ * is not found */
+extern int sepol_iface_modify(sepol_handle_t * handle,
+			      sepol_policydb_t * policydb,
+			      const sepol_iface_key_t * key,
+			      const sepol_iface_t * data);
+
+/* Iterate the interfaces
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_iface_iterate(sepol_handle_t * handle,
+			       const sepol_policydb_t * policydb,
+			       int (*fn) (const sepol_iface_t * iface,
+					  void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/module.h b/libsepol/include/sepol/module.h
new file mode 100644
index 0000000..ff27f96
--- /dev/null
+++ b/libsepol/include/sepol/module.h
@@ -0,0 +1,86 @@
+#ifndef _SEPOL_MODULE_H_
+#define _SEPOL_MODULE_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_module_package;
+typedef struct sepol_module_package sepol_module_package_t;
+
+/* Module package public interfaces. */
+
+extern int sepol_module_package_create(sepol_module_package_t ** p);
+
+extern void sepol_module_package_free(sepol_module_package_t * p);
+
+extern char *sepol_module_package_get_file_contexts(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t
+							 * p);
+
+extern int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+						  char *data, size_t len);
+
+extern char *sepol_module_package_get_seusers(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_seusers(sepol_module_package_t * p,
+					    char *data, size_t len);
+
+extern char *sepol_module_package_get_user_extra(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_user_extra_len(sepol_module_package_t *
+						      p);
+
+extern int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+					       char *data, size_t len);
+
+extern char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t
+							 * p);
+
+extern size_t
+sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_netfilter_contexts(sepol_module_package_t *
+						       p, char *data,
+						       size_t len);
+
+extern sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t
+							 * p);
+
+extern int sepol_link_packages(sepol_handle_t * handle,
+			       sepol_module_package_t * base,
+			       sepol_module_package_t ** modules,
+			       int num_modules, int verbose);
+
+extern int sepol_module_package_read(sepol_module_package_t * mod,
+				     struct sepol_policy_file *file,
+				     int verbose);
+
+extern int sepol_module_package_info(struct sepol_policy_file *file,
+				     int *type, char **name, char **version);
+
+extern int sepol_module_package_write(sepol_module_package_t * p,
+				      struct sepol_policy_file *file);
+
+/* Module linking/expanding public interfaces. */
+
+extern int sepol_link_modules(sepol_handle_t * handle,
+			      sepol_policydb_t * base,
+			      sepol_policydb_t ** modules,
+			      size_t len, int verbose);
+
+extern int sepol_expand_module(sepol_handle_t * handle,
+			       sepol_policydb_t * base,
+			       sepol_policydb_t * out, int verbose, int check);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/module_to_cil.h b/libsepol/include/sepol/module_to_cil.h
new file mode 100644
index 0000000..18bb3bf
--- /dev/null
+++ b/libsepol/include/sepol/module_to_cil.h
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+#include <sepol/module.h>
+#include <sepol/policydb/policydb.h>
+
+int sepol_module_policydb_to_cil(FILE *fp, struct policydb *pdb, int linked);
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg);
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg);
diff --git a/libsepol/include/sepol/node_record.h b/libsepol/include/sepol/node_record.h
new file mode 100644
index 0000000..e2d3e6d
--- /dev/null
+++ b/libsepol/include/sepol/node_record.h
@@ -0,0 +1,96 @@
+#ifndef _SEPOL_NODE_RECORD_H_
+#define _SEPOL_NODE_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_node;
+struct sepol_node_key;
+typedef struct sepol_node sepol_node_t;
+typedef struct sepol_node_key sepol_node_key_t;
+
+#define SEPOL_PROTO_IP4 0
+#define SEPOL_PROTO_IP6 1
+
+/* Key */
+extern int sepol_node_compare(const sepol_node_t * node,
+			      const sepol_node_key_t * key);
+
+extern int sepol_node_compare2(const sepol_node_t * node,
+			       const sepol_node_t * node2);
+
+extern int sepol_node_key_create(sepol_handle_t * handle,
+				 const char *addr,
+				 const char *mask,
+				 int proto, sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_unpack(const sepol_node_key_t * key,
+				  const char **addr,
+				  const char **mask, int *proto);
+
+extern int sepol_node_key_extract(sepol_handle_t * handle,
+				  const sepol_node_t * node,
+				  sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_free(sepol_node_key_t * key);
+
+/* Address */
+extern int sepol_node_get_addr(sepol_handle_t * handle,
+			       const sepol_node_t * node, char **addr);
+
+extern int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+				     const sepol_node_t * node,
+				     char **addr, size_t * addr_sz);
+
+extern int sepol_node_set_addr(sepol_handle_t * handle,
+			       sepol_node_t * node,
+			       int proto, const char *addr);
+
+extern int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+				     sepol_node_t * node,
+				     const char *addr, size_t addr_sz);
+
+/* Netmask */
+extern int sepol_node_get_mask(sepol_handle_t * handle,
+			       const sepol_node_t * node, char **mask);
+
+extern int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+				     const sepol_node_t * node,
+				     char **mask, size_t * mask_sz);
+
+extern int sepol_node_set_mask(sepol_handle_t * handle,
+			       sepol_node_t * node,
+			       int proto, const char *mask);
+
+extern int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+				     sepol_node_t * node,
+				     const char *mask, size_t mask_sz);
+
+/* Protocol */
+extern int sepol_node_get_proto(const sepol_node_t * node);
+
+extern void sepol_node_set_proto(sepol_node_t * node, int proto);
+
+extern const char *sepol_node_get_proto_str(int proto);
+
+/* Context */
+extern sepol_context_t *sepol_node_get_con(const sepol_node_t * node);
+
+extern int sepol_node_set_con(sepol_handle_t * handle,
+			      sepol_node_t * node, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node_ptr);
+
+extern int sepol_node_clone(sepol_handle_t * handle,
+			    const sepol_node_t * node,
+			    sepol_node_t ** node_ptr);
+
+extern void sepol_node_free(sepol_node_t * node);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/nodes.h b/libsepol/include/sepol/nodes.h
new file mode 100644
index 0000000..6fa534e
--- /dev/null
+++ b/libsepol/include/sepol/nodes.h
@@ -0,0 +1,44 @@
+#ifndef _SEPOL_NODES_H_
+#define _SEPOL_NODES_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/node_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle,
+			    const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a node exists */
+extern int sepol_node_exists(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     const sepol_node_key_t * key, int *response);
+
+/* Query a node - returns the node, or NULL if not found */
+extern int sepol_node_query(sepol_handle_t * handle,
+			    const sepol_policydb_t * policydb,
+			    const sepol_node_key_t * key,
+			    sepol_node_t ** response);
+
+/* Modify a node, or add it, if the key is not found */
+extern int sepol_node_modify(sepol_handle_t * handle,
+			     sepol_policydb_t * policydb,
+			     const sepol_node_key_t * key,
+			     const sepol_node_t * data);
+
+/* Iterate the nodes 
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_node_iterate(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      int (*fn) (const sepol_node_t * node,
+					 void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb.h b/libsepol/include/sepol/policydb.h
new file mode 100644
index 0000000..c3943e9
--- /dev/null
+++ b/libsepol/include/sepol/policydb.h
@@ -0,0 +1,148 @@
+#ifndef _SEPOL_POLICYDB_H_
+#define _SEPOL_POLICYDB_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_policy_file;
+typedef struct sepol_policy_file sepol_policy_file_t;
+
+struct sepol_policydb;
+typedef struct sepol_policydb sepol_policydb_t;
+
+/* Policy file public interfaces. */
+
+/* Create and free memory associated with a policy file. */
+extern int sepol_policy_file_create(sepol_policy_file_t ** pf);
+extern void sepol_policy_file_free(sepol_policy_file_t * pf);
+
+/*
+ * Set the policy file to represent a binary policy memory image.
+ * Subsequent operations using the policy file will read and write
+ * the image located at the specified address with the specified length.
+ * If 'len' is 0, then merely compute the necessary length upon  
+ * subsequent policydb write operations in order to determine the
+ * necessary buffer size to allocate.
+ */
+extern void sepol_policy_file_set_mem(sepol_policy_file_t * pf,
+				      char *data, size_t len);
+
+/*
+ * Get the size of the buffer needed to store a policydb write
+ * previously done on this policy file.
+ */
+extern int sepol_policy_file_get_len(sepol_policy_file_t * pf, size_t * len);
+
+/*
+ * Set the policy file to represent a FILE.
+ * Subsequent operations using the policy file will read and write
+ * to the FILE.
+ */
+extern void sepol_policy_file_set_fp(sepol_policy_file_t * pf, FILE * fp);
+
+/*
+ * Associate a handle with a policy file, for use in
+ * error reporting from subsequent calls that take the
+ * policy file as an argument.
+ */
+extern void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+					 sepol_handle_t * handle);
+
+/* Policydb public interfaces. */
+
+/* Create and free memory associated with a policydb. */
+extern int sepol_policydb_create(sepol_policydb_t ** p);
+extern void sepol_policydb_free(sepol_policydb_t * p);
+
+/* Legal types of policies that the policydb can represent. */
+#define SEPOL_POLICY_KERN	0
+#define SEPOL_POLICY_BASE	1
+#define SEPOL_POLICY_MOD	2
+
+/*
+ * Range of policy versions for the kernel policy type supported
+ * by this library.
+ */
+extern int sepol_policy_kern_vers_min(void);
+extern int sepol_policy_kern_vers_max(void);
+
+/*
+ * Set the policy type as specified, and automatically initialize the
+ * policy version accordingly to the maximum version supported for the
+ * policy type.  
+ * Returns -1 if the policy type is not legal.
+ */
+extern int sepol_policydb_set_typevers(sepol_policydb_t * p, unsigned int type);
+
+/*
+ * Set the policy version to a different value.
+ * Returns -1 if the policy version is not in the supported range for
+ * the (previously set) policy type.
+ */
+extern int sepol_policydb_set_vers(sepol_policydb_t * p, unsigned int vers);
+
+/* Set how to handle unknown class/perms. */
+#define SEPOL_DENY_UNKNOWN	    0
+#define SEPOL_REJECT_UNKNOWN	    2
+#define SEPOL_ALLOW_UNKNOWN	    4
+extern int sepol_policydb_set_handle_unknown(sepol_policydb_t * p,
+					     unsigned int handle_unknown);
+
+/* Set the target platform */
+#define SEPOL_TARGET_SELINUX 0
+#define SEPOL_TARGET_XEN     1
+extern int sepol_policydb_set_target_platform(sepol_policydb_t * p,
+					     int target_platform);
+
+/* 
+ * Read a policydb from a policy file.
+ * This automatically sets the type and version based on the 
+ * image contents.
+ */
+extern int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Write a policydb to a policy file.
+ * The generated image will be in the binary format corresponding 
+ * to the policy version associated with the policydb.
+ */
+extern int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Extract a policydb from a binary policy memory image.  
+ * This is equivalent to sepol_policydb_read with a policy file
+ * set to refer to memory.
+ */
+extern int sepol_policydb_from_image(sepol_handle_t * handle,
+				     void *data, size_t len,
+				     sepol_policydb_t * p);
+
+/*
+ * Generate a binary policy memory image from a policydb.  
+ * This is equivalent to sepol_policydb_write with a policy file
+ * set to refer to memory, but internally handles computing the 
+ * necessary length and allocating an appropriately sized memory
+ * buffer for the caller.  
+ */
+extern int sepol_policydb_to_image(sepol_handle_t * handle,
+				   sepol_policydb_t * p,
+				   void **newdata, size_t * newlen);
+
+/* 
+ * Check whether the policydb has MLS enabled.
+ */
+extern int sepol_policydb_mls_enabled(const sepol_policydb_t * p);
+
+/*
+ * Check whether the compatibility mode for SELinux network
+ * checks should be enabled when using this policy.
+ */
+extern int sepol_policydb_compat_net(const sepol_policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/avrule_block.h b/libsepol/include/sepol/policydb/avrule_block.h
new file mode 100644
index 0000000..ecd347b
--- /dev/null
+++ b/libsepol/include/sepol/policydb/avrule_block.h
@@ -0,0 +1,41 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 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
+ */
+
+#ifndef _SEPOL_AVRULE_BLOCK_H_
+#define _SEPOL_AVRULE_BLOCK_H_
+
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern avrule_block_t *avrule_block_create(void);
+extern void avrule_block_destroy(avrule_block_t * x);
+extern avrule_decl_t *avrule_decl_create(uint32_t decl_id);
+extern void avrule_decl_destroy(avrule_decl_t * x);
+extern void avrule_block_list_destroy(avrule_block_t * x);
+extern avrule_decl_t *get_avrule_decl(policydb_t * p, uint32_t decl_id);
+extern cond_list_t *get_decl_cond_list(policydb_t * p,
+				       avrule_decl_t * decl,
+				       cond_list_t * cond);
+extern int is_id_enabled(char *id, policydb_t * p, int symbol_table);
+extern int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
new file mode 100644
index 0000000..d3ea84e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/avtab.h
@@ -0,0 +1,148 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * 	Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 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
+ */
+
+/* FLASK */
+
+/*
+ * An access vector table (avtab) is a hash table
+ * of access vectors and transition types indexed 
+ * by a type pair and a class.  An access vector
+ * table is used to represent the type enforcement
+ * tables.
+ */
+
+#ifndef _SEPOL_POLICYDB_AVTAB_H_
+#define _SEPOL_POLICYDB_AVTAB_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+typedef struct avtab_key {
+	uint16_t source_type;
+	uint16_t target_type;
+	uint16_t target_class;
+#define AVTAB_ALLOWED		0x0001
+#define AVTAB_AUDITALLOW	0x0002
+#define AVTAB_AUDITDENY		0x0004
+#define AVTAB_NEVERALLOW	0x0080
+#define AVTAB_AV		(AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION	0x0010
+#define AVTAB_MEMBER		0x0020
+#define AVTAB_CHANGE		0x0040
+#define AVTAB_TYPE		(AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_XPERMS_ALLOWED	0x0100
+#define AVTAB_XPERMS_AUDITALLOW	0x0200
+#define AVTAB_XPERMS_DONTAUDIT	0x0400
+#define AVTAB_XPERMS_NEVERALLOW	0x0800
+#define AVTAB_XPERMS		(AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | AVTAB_XPERMS_DONTAUDIT)
+#define AVTAB_ENABLED_OLD	0x80000000
+#define AVTAB_ENABLED		0x8000	/* reserved for used in cond_avtab */
+	uint16_t specified;	/* what fields are specified */
+} avtab_key_t;
+
+typedef struct avtab_extended_perms {
+
+#define AVTAB_XPERMS_IOCTLFUNCTION	0x01
+#define AVTAB_XPERMS_IOCTLDRIVER	0x02
+	/* extension of the avtab_key specified */
+	uint8_t specified;
+	uint8_t driver;
+	uint32_t perms[8];
+} avtab_extended_perms_t;
+
+typedef struct avtab_datum {
+	uint32_t data;		/* access vector or type */
+	avtab_extended_perms_t *xperms;
+} avtab_datum_t;
+
+typedef struct avtab_node *avtab_ptr_t;
+
+struct avtab_node {
+	avtab_key_t key;
+	avtab_datum_t datum;
+	avtab_ptr_t next;
+	void *parse_context;	/* generic context pointer used by parser;
+				 * not saved in binary policy */
+	unsigned merged;	/* flag for avtab_write only;
+				   not saved in binary policy */
+};
+
+typedef struct avtab {
+	avtab_ptr_t *htable;
+	uint32_t nel;		/* number of elements */
+	uint32_t nslot;         /* number of hash slots */
+	uint32_t mask;          /* mask to compute hash func */
+} avtab_t;
+
+extern int avtab_init(avtab_t *);
+extern int avtab_alloc(avtab_t *, uint32_t);
+extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
+
+extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
+
+extern void avtab_destroy(avtab_t * h);
+
+extern int avtab_map(avtab_t * h,
+		     int (*apply) (avtab_key_t * k,
+				   avtab_datum_t * d, void *args), void *args);
+
+extern void avtab_hash_eval(avtab_t * h, char *tag);
+
+struct policy_file;
+extern int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+			   int (*insert) (avtab_t * a, avtab_key_t * k,
+					  avtab_datum_t * d, void *p), void *p);
+
+extern int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers);
+
+extern avtab_ptr_t avtab_insert_nonunique(avtab_t * h, avtab_key_t * key,
+					  avtab_datum_t * datum);
+
+extern avtab_ptr_t avtab_insert_with_parse_context(avtab_t * h,
+						   avtab_key_t * key,
+						   avtab_datum_t * datum,
+						   void *parse_context);
+
+extern avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key);
+
+extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
+
+#define MAX_AVTAB_HASH_BITS 20
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+/* avtab_alloc uses one bucket per 2-4 elements, so adjust to get maximum buckets */
+#define MAX_AVTAB_SIZE (MAX_AVTAB_HASH_BUCKETS << 1)
+
+__END_DECLS
+#endif				/* _AVTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/conditional.h b/libsepol/include/sepol/policydb/conditional.h
new file mode 100644
index 0000000..cd2a9a9
--- /dev/null
+++ b/libsepol/include/sepol/policydb/conditional.h
@@ -0,0 +1,140 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 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
+ */
+
+#ifndef _SEPOL_POLICYDB_CONDITIONAL_H_
+#define _SEPOL_POLICYDB_CONDITIONAL_H_
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define COND_EXPR_MAXDEPTH 10
+
+/* this is the max unique bools in a conditional expression
+ * for which we precompute all outcomes for the expression.
+ *
+ * NOTE - do _NOT_ use value greater than 5 because
+ * cond_node_t->expr_pre_comp can only hold at most 32 values
+ */
+#define COND_MAX_BOOLS 5
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+typedef struct cond_expr {
+#define COND_BOOL	1	/* plain bool */
+#define COND_NOT	2	/* !bool */
+#define COND_OR		3	/* bool || bool */
+#define COND_AND	4	/* bool && bool */
+#define COND_XOR	5	/* bool ^ bool */
+#define COND_EQ		6	/* bool == bool */
+#define COND_NEQ	7	/* bool != bool */
+#define COND_LAST	COND_NEQ
+	uint32_t expr_type;
+	uint32_t bool;
+	struct cond_expr *next;
+} cond_expr_t;
+
+/*
+ * Each cond_node_t contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This 
+ * struct is for that list.
+ */
+typedef struct cond_av_list {
+	avtab_ptr_t node;
+	struct cond_av_list *next;
+} cond_av_list_t;
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+typedef struct cond_node {
+	int cur_state;
+	cond_expr_t *expr;
+	/* these true/false lists point into te_avtab when that is used */
+	cond_av_list_t *true_list;
+	cond_av_list_t *false_list;
+	/* and these are used during parsing and for modules */
+	avrule_t *avtrue_list;
+	avrule_t *avfalse_list;
+	/* these fields are not written to binary policy */
+	unsigned int nbools;
+	uint32_t bool_ids[COND_MAX_BOOLS];
+	uint32_t expr_pre_comp;
+	struct cond_node *next;
+	/* a tunable conditional, calculated and used at expansion */
+#define	COND_NODE_FLAGS_TUNABLE	0x01
+	uint32_t flags;
+} cond_node_t;
+
+extern int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr);
+extern cond_expr_t *cond_copy_expr(cond_expr_t * expr);
+
+extern int cond_expr_equal(cond_node_t * a, cond_node_t * b);
+extern int cond_normalize_expr(policydb_t * p, cond_node_t * cn);
+extern void cond_node_destroy(cond_node_t * node);
+extern void cond_expr_destroy(cond_expr_t * expr);
+
+extern cond_node_t *cond_node_find(policydb_t * p,
+				   cond_node_t * needle, cond_node_t * haystack,
+				   int *was_created);
+
+extern cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node);
+
+extern cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+				     cond_node_t * cn);
+
+extern int evaluate_conds(policydb_t * p);
+
+extern avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+					  cond_av_list_t * cond_list);
+
+extern void cond_av_list_destroy(cond_av_list_t * list);
+
+extern void cond_optimize_lists(cond_list_t * cl);
+
+extern int cond_policydb_init(policydb_t * p);
+extern void cond_policydb_destroy(policydb_t * p);
+extern void cond_list_destroy(cond_list_t * list);
+
+extern int cond_init_bool_indexes(policydb_t * p);
+extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
+
+extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum,
+			   void *datap);
+
+extern int cond_read_bool(policydb_t * p, hashtab_t h, struct policy_file *fp);
+
+extern int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp);
+
+extern void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+			    struct sepol_av_decision *avd);
+
+__END_DECLS
+#endif				/* _CONDITIONAL_H_ */
diff --git a/libsepol/include/sepol/policydb/constraint.h b/libsepol/include/sepol/policydb/constraint.h
new file mode 100644
index 0000000..ae7034d
--- /dev/null
+++ b/libsepol/include/sepol/policydb/constraint.h
@@ -0,0 +1,79 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A constraint is a condition that must be satisfied in
+ * order for one or more permissions to be granted.  
+ * Constraints are used to impose additional restrictions
+ * beyond the type-based rules in `te' or the role-based
+ * transition rules in `rbac'.  Constraints are typically
+ * used to prevent a process from transitioning to a new user 
+ * identity or role unless it is in a privileged type.
+ * Constraints are likewise typically used to prevent a
+ * process from labeling an object with a different user
+ * identity.   
+ */
+
+#ifndef _SEPOL_POLICYDB_CONSTRAINT_H_
+#define _SEPOL_POLICYDB_CONSTRAINT_H_
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+
+__BEGIN_DECLS
+
+#define CEXPR_MAXDEPTH 5
+
+struct type_set;
+
+typedef struct constraint_expr {
+#define CEXPR_NOT		1	/* not expr */
+#define CEXPR_AND		2	/* expr and expr */
+#define CEXPR_OR		3	/* expr or expr */
+#define CEXPR_ATTR		4	/* attr op attr */
+#define CEXPR_NAMES		5	/* attr op names */
+	uint32_t expr_type;	/* expression type */
+
+#define CEXPR_USER 1		/* user */
+#define CEXPR_ROLE 2		/* role */
+#define CEXPR_TYPE 4		/* type */
+#define CEXPR_TARGET 8		/* target if set, source otherwise */
+#define CEXPR_XTARGET 16	/* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32		/* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64		/* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128		/* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256		/* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512		/* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024		/* low level 2 vs. high level 2 */
+	uint32_t attr;		/* attribute */
+
+#define CEXPR_EQ     1		/* == or eq */
+#define CEXPR_NEQ    2		/* != */
+#define CEXPR_DOM    3		/* dom */
+#define CEXPR_DOMBY  4		/* domby  */
+#define CEXPR_INCOMP 5		/* incomp */
+	uint32_t op;		/* operator */
+
+	ebitmap_t names;	/* names */
+	struct type_set *type_names;
+
+	struct constraint_expr *next;	/* next expression */
+} constraint_expr_t;
+
+typedef struct constraint_node {
+	sepol_access_vector_t permissions;	/* constrained permissions */
+	constraint_expr_t *expr;	/* constraint on permissions */
+	struct constraint_node *next;	/* next constraint */
+} constraint_node_t;
+
+struct policydb;
+
+extern int constraint_expr_init(constraint_expr_t * expr);
+extern void constraint_expr_destroy(constraint_expr_t * expr);
+
+__END_DECLS
+#endif				/* _CONSTRAINT_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/context.h b/libsepol/include/sepol/policydb/context.h
new file mode 100644
index 0000000..dbb7c3e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/context.h
@@ -0,0 +1,99 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy.  Security contexts are
+ * externally represented as variable-length strings
+ * that can be interpreted by a user or application
+ * with an understanding of the security policy. 
+ * Internally, the security server uses a simple
+ * structure.  This structure is private to the
+ * security server and can be changed without affecting
+ * clients of the security server.
+ */
+
+#ifndef _SEPOL_POLICYDB_CONTEXT_H_
+#define _SEPOL_POLICYDB_CONTEXT_H_
+
+#include <stddef.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/mls_types.h>
+
+__BEGIN_DECLS
+
+/*
+ * A security context consists of an authenticated user
+ * identity, a role, a type and a MLS range.
+ */
+typedef struct context_struct {
+	uint32_t user;
+	uint32_t role;
+	uint32_t type;
+	mls_range_t range;
+} context_struct_t;
+
+static inline void mls_context_init(context_struct_t * c)
+{
+	mls_range_init(&c->range);
+}
+
+static inline int mls_context_cpy(context_struct_t * dst,
+				  context_struct_t * src)
+{
+
+	if (mls_range_cpy(&dst->range, &src->range) < 0)
+		return -1;
+
+	return 0;
+}
+
+static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+	return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) &&
+		mls_level_eq(&c1->range.level[1], &c2->range.level[1]));
+
+}
+
+static inline void mls_context_destroy(context_struct_t * c)
+{
+	if (c == NULL)
+		return;
+
+	mls_range_destroy(&c->range);
+	mls_context_init(c);
+}
+
+static inline void context_init(context_struct_t * c)
+{
+	memset(c, 0, sizeof(*c));
+}
+
+static inline int context_cpy(context_struct_t * dst, context_struct_t * src)
+{
+	dst->user = src->user;
+	dst->role = src->role;
+	dst->type = src->type;
+	return mls_context_cpy(dst, src);
+}
+
+static inline void context_destroy(context_struct_t * c)
+{
+	if (c == NULL)
+		return;
+
+	c->user = c->role = c->type = 0;
+	mls_context_destroy(c);
+}
+
+static inline int context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+	return ((c1->user == c2->user) &&
+		(c1->role == c2->role) &&
+		(c1->type == c2->type) && mls_context_cmp(c1, c2));
+}
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/ebitmap.h b/libsepol/include/sepol/policydb/ebitmap.h
new file mode 100644
index 0000000..7b3508d
--- /dev/null
+++ b/libsepol/include/sepol/policydb/ebitmap.h
@@ -0,0 +1,98 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * An extensible bitmap is a bitmap that supports an 
+ * arbitrary number of bits.  Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ */
+
+#ifndef _SEPOL_POLICYDB_EBITMAP_H_
+#define _SEPOL_POLICYDB_EBITMAP_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define MAPTYPE uint64_t	/* portion of bitmap in each node */
+#define MAPSIZE (sizeof(MAPTYPE) * 8)	/* number of bits in node bitmap */
+#define MAPBIT  1ULL		/* a bit in the node bitmap */
+
+typedef struct ebitmap_node {
+	uint32_t startbit;	/* starting position in the total bitmap */
+	MAPTYPE map;		/* this node's portion of the bitmap */
+	struct ebitmap_node *next;
+} ebitmap_node_t;
+
+typedef struct ebitmap {
+	ebitmap_node_t *node;	/* first node in the bitmap */
+	uint32_t highbit;	/* highest position in the total bitmap */
+} ebitmap_t;
+
+#define ebitmap_length(e) ((e)->highbit)
+#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+#define ebitmap_startnode(e) ((e)->node)
+
+static inline unsigned int ebitmap_start(const ebitmap_t * e,
+					 ebitmap_node_t ** n)
+{
+
+	*n = e->node;
+	return ebitmap_startbit(e);
+}
+
+static inline void ebitmap_init(ebitmap_t * e)
+{
+	memset(e, 0, sizeof(*e));
+}
+
+static inline unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit)
+{
+	if ((bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next) {
+		*n = (*n)->next;
+		return (*n)->startbit;
+	}
+
+	return (bit + 1);
+}
+
+static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit)
+{
+	if (n->map & (MAPBIT << (bit - n->startbit)))
+		return 1;
+	return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+	for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1);
+extern int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2);
+extern int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2);
+extern int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit);
+extern int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit);
+extern unsigned int ebitmap_cardinality(ebitmap_t *e1);
+extern int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2);
+extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src);
+extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2);
+extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit);
+extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value);
+extern void ebitmap_destroy(ebitmap_t * e);
+extern int ebitmap_read(ebitmap_t * e, void *fp);
+
+__END_DECLS
+#endif				/* _EBITMAP_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/expand.h b/libsepol/include/sepol/policydb/expand.h
new file mode 100644
index 0000000..a8de41e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/expand.h
@@ -0,0 +1,83 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *	    Joshua Brindle <jbrindle@tresys.com>
+ *          Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 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
+ */
+
+#ifndef _SEPOL_POLICYDB_EXPAND_H
+#define _SEPOL_POLICYDB_EXPAND_H
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/conditional.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * Expand only the avrules for a module. It is valid for this function
+ * to expand base into itself (i.e.  base == out); the typemap for
+ * this special case should map type[i] to i+1.  Likewise the boolmap
+ * should map bool[i] to i + 1.  This function optionally expands
+ * neverallow rules. If neverallow rules are expanded, there is no
+ * need to copy them and doing so could cause duplicate entries when
+ * base == out.  If the neverallow rules are not expanded, they are
+ * just copied to the destination policy so that assertion checking
+ * can be performed after expand.  No assertion or hierarchy checking
+ * is performed by this function.
+ */
+extern int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+				 policydb_t * out, uint32_t * typemap, uint32_t * boolmap,
+				 uint32_t * rolemap, uint32_t * usermap,
+				 int verbose, int expand_neverallow);
+/*
+ * Expand all parts of a module. Neverallow rules are not expanded (only
+ * copied). It is not valid to expand base into itself. If check is non-zero,
+ * performs hierarchy and assertion checking.
+ */
+extern int expand_module(sepol_handle_t * handle,
+			 policydb_t * base, policydb_t * out,
+			 int verbose, int check);
+extern int convert_type_ebitmap(ebitmap_t * src, ebitmap_t * dst,
+				uint32_t * typemap);
+extern int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+				   type_set_t * set, ebitmap_t * types,
+				   unsigned char alwaysexpand);
+extern int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+			   unsigned char alwaysexpand);
+extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap);
+extern int mls_semantic_level_expand(mls_semantic_level_t *sl, mls_level_t *l,
+                                     policydb_t *p, sepol_handle_t *h);
+extern int mls_semantic_range_expand(mls_semantic_range_t *sr, mls_range_t *r,
+                                     policydb_t *p, sepol_handle_t *h);
+extern int expand_rule(sepol_handle_t * handle,
+		       policydb_t * source_pol,
+		       avrule_t * source_rule, avtab_t * dest_avtab,
+		       cond_av_list_t ** cond, cond_av_list_t ** other,
+		       int enabled);
+
+extern int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa);
+
+extern int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+			       cond_av_list_t ** newl, avtab_t * expa);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/flask.h b/libsepol/include/sepol/policydb/flask.h
new file mode 100644
index 0000000..3134284
--- /dev/null
+++ b/libsepol/include/sepol/policydb/flask.h
@@ -0,0 +1,94 @@
+/* This file is automatically generated.  Do not edit. */
+#ifndef _SEPOL_POLICYDB_FLASK_H_
+#define _SEPOL_POLICYDB_FLASK_H_
+
+/*
+ * Security object class definitions
+ */
+#define SECCLASS_SECURITY                                1
+#define SECCLASS_PROCESS                                 2
+#define SECCLASS_SYSTEM                                  3
+#define SECCLASS_CAPABILITY                              4
+#define SECCLASS_FILESYSTEM                              5
+#define SECCLASS_FILE                                    6
+#define SECCLASS_DIR                                     7
+#define SECCLASS_FD                                      8
+#define SECCLASS_LNK_FILE                                9
+#define SECCLASS_CHR_FILE                                10
+#define SECCLASS_BLK_FILE                                11
+#define SECCLASS_SOCK_FILE                               12
+#define SECCLASS_FIFO_FILE                               13
+#define SECCLASS_SOCKET                                  14
+#define SECCLASS_TCP_SOCKET                              15
+#define SECCLASS_UDP_SOCKET                              16
+#define SECCLASS_RAWIP_SOCKET                            17
+#define SECCLASS_NODE                                    18
+#define SECCLASS_NETIF                                   19
+#define SECCLASS_NETLINK_SOCKET                          20
+#define SECCLASS_PACKET_SOCKET                           21
+#define SECCLASS_KEY_SOCKET                              22
+#define SECCLASS_UNIX_STREAM_SOCKET                      23
+#define SECCLASS_UNIX_DGRAM_SOCKET                       24
+#define SECCLASS_SEM                                     25
+#define SECCLASS_MSG                                     26
+#define SECCLASS_MSGQ                                    27
+#define SECCLASS_SHM                                     28
+#define SECCLASS_IPC                                     29
+#define SECCLASS_PASSWD                                  30
+#define SECCLASS_DRAWABLE                                31
+#define SECCLASS_WINDOW                                  32
+#define SECCLASS_GC                                      33
+#define SECCLASS_FONT                                    34
+#define SECCLASS_COLORMAP                                35
+#define SECCLASS_PROPERTY                                36
+#define SECCLASS_CURSOR                                  37
+#define SECCLASS_XCLIENT                                 38
+#define SECCLASS_XINPUT                                  39
+#define SECCLASS_XSERVER                                 40
+#define SECCLASS_XEXTENSION                              41
+#define SECCLASS_PAX                                     42
+#define SECCLASS_NETLINK_ROUTE_SOCKET                    43
+#define SECCLASS_NETLINK_FIREWALL_SOCKET                 44
+#define SECCLASS_NETLINK_TCPDIAG_SOCKET                  45
+#define SECCLASS_NETLINK_NFLOG_SOCKET                    46
+#define SECCLASS_NETLINK_XFRM_SOCKET                     47
+#define SECCLASS_NETLINK_SELINUX_SOCKET                  48
+#define SECCLASS_NETLINK_AUDIT_SOCKET                    49
+#define SECCLASS_NETLINK_IP6FW_SOCKET                    50
+#define SECCLASS_NETLINK_DNRT_SOCKET                     51
+#define SECCLASS_DBUS                                    52
+
+/*
+ * Security identifier indices for initial entities
+ */
+#define SECINITSID_KERNEL                               1
+#define SECINITSID_SECURITY                             2
+#define SECINITSID_UNLABELED                            3
+#define SECINITSID_FS                                   4
+#define SECINITSID_FILE                                 5
+#define SECINITSID_FILE_LABELS                          6
+#define SECINITSID_INIT                                 7
+#define SECINITSID_ANY_SOCKET                           8
+#define SECINITSID_PORT                                 9
+#define SECINITSID_NETIF                                10
+#define SECINITSID_NETMSG                               11
+#define SECINITSID_NODE                                 12
+#define SECINITSID_IGMP_PACKET                          13
+#define SECINITSID_ICMP_SOCKET                          14
+#define SECINITSID_TCP_SOCKET                           15
+#define SECINITSID_SYSCTL_MODPROBE                      16
+#define SECINITSID_SYSCTL                               17
+#define SECINITSID_SYSCTL_FS                            18
+#define SECINITSID_SYSCTL_KERNEL                        19
+#define SECINITSID_SYSCTL_NET                           20
+#define SECINITSID_SYSCTL_NET_UNIX                      21
+#define SECINITSID_SYSCTL_VM                            22
+#define SECINITSID_SYSCTL_DEV                           23
+#define SECINITSID_KMOD                                 24
+#define SECINITSID_POLICY                               25
+#define SECINITSID_SCMP_PACKET                          26
+#define SECINITSID_DEVNULL                              27
+
+#define SECINITSID_NUM                                  27
+
+#endif
diff --git a/libsepol/include/sepol/policydb/flask_types.h b/libsepol/include/sepol/policydb/flask_types.h
new file mode 100644
index 0000000..2a59565
--- /dev/null
+++ b/libsepol/include/sepol/policydb/flask_types.h
@@ -0,0 +1,65 @@
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+#ifndef _SEPOL_POLICYDB_FLASK_TYPES_H_
+#define _SEPOL_POLICYDB_FLASK_TYPES_H_
+
+/*
+ * The basic Flask types and constants.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * A security context is a set of security attributes 
+ * associated with each subject and object controlled
+ * by the security policy.  The security context type
+ * is defined as a variable-length string that can be
+ * interpreted by any application or user with an 
+ * understanding of the security policy.
+ */
+typedef char *sepol_security_context_t;
+
+/*
+ * An access vector (AV) is a collection of related permissions
+ * for a pair of SIDs.  The bits within an access vector
+ * are interpreted differently depending on the class of
+ * the object.  The access vector interpretations are specified
+ * in flask/access_vectors, and the corresponding constants
+ * for permissions are defined in the automatically generated
+ * header file av_permissions.h.
+ */
+typedef uint32_t sepol_access_vector_t;
+
+/*
+ * Each object class is identified by a fixed-size value.
+ * The set of security classes is specified in flask/security_classes, 
+ * with the corresponding constants defined in the automatically 
+ * generated header file flask.h.
+ */
+typedef uint16_t sepol_security_class_t;
+#define SEPOL_SECCLASS_NULL			0x0000	/* no class */
+
+#define SELINUX_MAGIC 0xf97cff8c
+#define SELINUX_MOD_MAGIC 0xf97cff8d
+
+typedef uint32_t sepol_security_id_t;
+#define SEPOL_SECSID_NULL 0
+
+struct sepol_av_decision {
+	sepol_access_vector_t allowed;
+	sepol_access_vector_t decided;
+	sepol_access_vector_t auditallow;
+	sepol_access_vector_t auditdeny;
+	uint32_t seqno;
+};
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
new file mode 100644
index 0000000..0afc59c
--- /dev/null
+++ b/libsepol/include/sepol/policydb/hashtab.h
@@ -0,0 +1,140 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A hash table (hashtab) maintains associations between
+ * key values and datum values.  The type of the key values 
+ * and the type of the datum values is arbitrary.  The
+ * functions for hash computation and key comparison are
+ * provided by the creator of the table.
+ */
+
+#ifndef _SEPOL_POLICYDB_HASHTAB_H_
+#define _SEPOL_POLICYDB_HASHTAB_H_
+
+#include <sepol/errcodes.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef char *hashtab_key_t;	/* generic key type */
+typedef void *hashtab_datum_t;	/* generic datum type */
+
+typedef struct hashtab_node *hashtab_ptr_t;
+
+typedef struct hashtab_node {
+	hashtab_key_t key;
+	hashtab_datum_t datum;
+	hashtab_ptr_t next;
+} hashtab_node_t;
+
+typedef struct hashtab_val {
+	hashtab_ptr_t *htable;	/* hash table */
+	unsigned int size;	/* number of slots in hash table */
+	uint32_t nel;		/* number of elements in hash table */
+	unsigned int (*hash_value) (struct hashtab_val * h, hashtab_key_t key);	/* hash function */
+	int (*keycmp) (struct hashtab_val * h, hashtab_key_t key1, hashtab_key_t key2);	/* key comparison function */
+} hashtab_val_t;
+
+typedef hashtab_val_t *hashtab_t;
+
+/*
+   Creates a new hash table with the specified characteristics.
+
+   Returns NULL if insufficent space is available or
+   the new hash table otherwise.
+ */
+extern hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+							    const hashtab_key_t
+							    key),
+				int (*keycmp) (hashtab_t h,
+					       const hashtab_key_t key1,
+					       const hashtab_key_t key2),
+				unsigned int size);
+/*
+   Inserts the specified (key, datum) pair into the specified hash table.
+
+   Returns SEPOL_ENOMEM if insufficient space is available or
+   SEPOL_EEXIST  if there is already an entry with the same key or
+   SEPOL_OK otherwise.
+ */
+extern int hashtab_insert(hashtab_t h, hashtab_key_t k, hashtab_datum_t d);
+
+/*
+   Removes the entry with the specified key from the hash table.
+   Applies the specified destroy function to (key,datum,args) for
+   the entry.
+
+   Returns SEPOL_ENOENT if no entry has the specified key or
+   SEPOL_OK otherwise.
+ */
+extern int hashtab_remove(hashtab_t h, hashtab_key_t k,
+			  void (*destroy) (hashtab_key_t k,
+					   hashtab_datum_t d,
+					   void *args), void *args);
+
+/*
+   Insert or replace the specified (key, datum) pair in the specified
+   hash table.  If an entry for the specified key already exists,
+   then the specified destroy function is applied to (key,datum,args)
+   for the entry prior to replacing the entry's contents.
+
+   Returns SEPOL_ENOMEM if insufficient space is available or
+   SEPOL_OK otherwise.
+ */
+extern int hashtab_replace(hashtab_t h, hashtab_key_t k, hashtab_datum_t d,
+			   void (*destroy) (hashtab_key_t k,
+					    hashtab_datum_t d,
+					    void *args), void *args);
+
+/*
+   Searches for the entry with the specified key in the hash table.
+
+   Returns NULL if no entry has the specified key or
+   the datum of the entry otherwise.
+ */
+extern hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t k);
+
+/*
+   Destroys the specified hash table.
+ */
+extern void hashtab_destroy(hashtab_t h);
+
+/*
+   Applies the specified apply function to (key,datum,args)
+   for each entry in the specified hash table.
+
+   The order in which the function is applied to the entries
+   is dependent upon the internal structure of the hash table.
+
+   If apply returns a non-zero status, then hashtab_map will cease
+   iterating through the hash table and will propagate the error
+   return to its caller.
+ */
+extern int hashtab_map(hashtab_t h,
+		       int (*apply) (hashtab_key_t k,
+				     hashtab_datum_t d,
+				     void *args), void *args);
+
+/*
+   Same as hashtab_map, except that if apply returns a non-zero status,
+   then the (key,datum) pair will be removed from the hashtab and the
+   destroy function will be applied to (key,datum,args).
+ */
+extern void hashtab_map_remove_on_error(hashtab_t h,
+					int (*apply) (hashtab_key_t k,
+						      hashtab_datum_t d,
+						      void *args),
+					void (*destroy) (hashtab_key_t k,
+							 hashtab_datum_t d,
+							 void *args),
+					void *args);
+
+extern void hashtab_hash_eval(hashtab_t h, char *tag);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/hierarchy.h b/libsepol/include/sepol/policydb/hierarchy.h
new file mode 100644
index 0000000..88bc02e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/hierarchy.h
@@ -0,0 +1,47 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *	    Joshua Brindle <jbrindle@tresys.com>
+ *          Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 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
+ */
+
+#ifndef _SEPOL_POLICYDB_HIERARCHY_H_
+#define _SEPOL_POLICYDB_HIERARCHY_H_
+
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p);
+
+extern void bounds_destroy_bad(avtab_ptr_t cur);
+extern int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+			     uint32_t parent, avtab_ptr_t *bad, int *numbad);
+
+extern int bounds_check_users(sepol_handle_t *handle, policydb_t *p);
+extern int bounds_check_roles(sepol_handle_t *handle, policydb_t *p);
+extern int bounds_check_types(sepol_handle_t *handle, policydb_t *p);
+
+extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/link.h b/libsepol/include/sepol/policydb/link.h
new file mode 100644
index 0000000..7c7c9be
--- /dev/null
+++ b/libsepol/include/sepol/policydb/link.h
@@ -0,0 +1,24 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *	    Joshua Brindle <jbrindle@tresys.com>
+ *          Karl MacMillan <kmacmillan@mentalrootkit.com>
+ */
+
+#ifndef _SEPOL_POLICYDB_LINK_H
+#define _SEPOL_POLICYDB_LINK_H
+
+#include <sepol/handle.h>
+#include <sepol/errcodes.h>
+#include <sepol/policydb/policydb.h>
+
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int link_modules(sepol_handle_t * handle,
+			policydb_t * b, policydb_t ** mods, int len,
+			int verbose);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/mls_types.h b/libsepol/include/sepol/policydb/mls_types.h
new file mode 100644
index 0000000..4bf7367
--- /dev/null
+++ b/libsepol/include/sepol/policydb/mls_types.h
@@ -0,0 +1,156 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_MLS_TYPES_H_
+#define _SEPOL_POLICYDB_MLS_TYPES_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct mls_level {
+	uint32_t sens;		/* sensitivity */
+	ebitmap_t cat;		/* category set */
+} mls_level_t;
+
+typedef struct mls_range {
+	mls_level_t level[2];	/* low == level[0], high == level[1] */
+} mls_range_t;
+
+static inline int mls_level_cpy(struct mls_level *dst, struct mls_level *src)
+{
+
+	dst->sens = src->sens;
+	if (ebitmap_cpy(&dst->cat, &src->cat) < 0)
+		return -1;
+	return 0;
+}
+
+static inline void mls_level_init(struct mls_level *level)
+{
+
+	memset(level, 0, sizeof(mls_level_t));
+}
+
+static inline void mls_level_destroy(struct mls_level *level)
+{
+
+	if (level == NULL)
+		return;
+
+	ebitmap_destroy(&level->cat);
+	mls_level_init(level);
+}
+
+static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2)
+{
+	return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2)
+{
+	return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
+
+static inline int mls_range_cpy(mls_range_t * dst, mls_range_t * src)
+{
+
+	if (mls_level_cpy(&dst->level[0], &src->level[0]) < 0)
+		goto err;
+
+	if (mls_level_cpy(&dst->level[1], &src->level[1]) < 0)
+		goto err_destroy;
+
+	return 0;
+
+      err_destroy:
+	mls_level_destroy(&dst->level[0]);
+
+      err:
+	return -1;
+}
+
+static inline void mls_range_init(struct mls_range *r)
+{
+	mls_level_init(&r->level[0]);
+	mls_level_init(&r->level[1]);
+}
+
+static inline void mls_range_destroy(struct mls_range *r)
+{
+	mls_level_destroy(&r->level[0]);
+	mls_level_destroy(&r->level[1]);
+}
+
+static inline int mls_range_eq(struct mls_range *r1, struct mls_range *r2)
+{
+	return (mls_level_eq(&r1->level[0], &r2->level[0]) &&
+	        mls_level_eq(&r1->level[1], &r2->level[1]));
+}
+
+typedef struct mls_semantic_cat {
+	uint32_t low;	/* first bit this struct represents */
+	uint32_t high;	/* last bit represented - equals low for a single cat */
+	struct mls_semantic_cat *next;
+} mls_semantic_cat_t;
+
+typedef struct mls_semantic_level {
+	uint32_t sens;
+	mls_semantic_cat_t *cat;
+} mls_semantic_level_t;
+
+typedef struct mls_semantic_range {
+	mls_semantic_level_t level[2];
+} mls_semantic_range_t;
+
+extern void mls_semantic_cat_init(mls_semantic_cat_t *c);
+extern void mls_semantic_cat_destroy(mls_semantic_cat_t *c);
+extern void mls_semantic_level_init(mls_semantic_level_t *l);
+extern void mls_semantic_level_destroy(mls_semantic_level_t *l);
+extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, mls_semantic_level_t *src);
+extern void mls_semantic_range_init(mls_semantic_range_t *r);
+extern void mls_semantic_range_destroy(mls_semantic_range_t *r);
+extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, mls_semantic_range_t *src);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/module.h b/libsepol/include/sepol/policydb/module.h
new file mode 100644
index 0000000..3fe560c
--- /dev/null
+++ b/libsepol/include/sepol/policydb/module.h
@@ -0,0 +1,52 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2004-2005 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
+ */
+
+#ifndef _SEPOL_POLICYDB_MODULE_H_
+#define _SEPOL_POLICYDB_MODULE_H_
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <sepol/module.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sys/cdefs.h>
+
+#define SEPOL_MODULE_PACKAGE_MAGIC 0xf97cff8f
+
+__BEGIN_DECLS
+
+struct sepol_module_package {
+	sepol_policydb_t *policy;
+	uint32_t version;
+	char *file_contexts;
+	size_t file_contexts_len;
+	char *seusers;
+	size_t seusers_len;
+	char *user_extra;
+	size_t user_extra_len;
+	char *netfilter_contexts;
+	size_t netfilter_contexts_len;
+};
+
+extern int sepol_module_package_init(sepol_module_package_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/polcaps.h b/libsepol/include/sepol/policydb/polcaps.h
new file mode 100644
index 0000000..74b7c9e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/polcaps.h
@@ -0,0 +1,25 @@
+#ifndef _SEPOL_POLICYDB_POLCAPS_H_
+#define _SEPOL_POLICYDB_POLCAPS_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Policy capabilities */
+enum {
+	POLICYDB_CAPABILITY_NETPEER,
+	POLICYDB_CAPABILITY_OPENPERM,
+	POLICYDB_CAPABILITY_REDHAT1, /* reserved for RH testing of ptrace_child */
+	POLICYDB_CAPABILITY_ALWAYSNETWORK,
+	__POLICYDB_CAPABILITY_MAX
+};
+#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+
+/* Convert a capability name to number. */
+extern int sepol_polcap_getnum(const char *name);
+
+/* Convert a capability number to name. */
+extern const char *sepol_polcap_getname(int capnum);
+
+__END_DECLS
+#endif /* _SEPOL_POLICYDB_POLCAPS_H_ */
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
new file mode 100644
index 0000000..26cec13
--- /dev/null
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -0,0 +1,774 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ *	    Karl MacMillan <kmacmillan@tresys.com>
+ *	    Jason Tang <jtang@tresys.com>
+ *	    
+ *	Module support
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc.  James Morris <jmorris@redhat.com>
+ *
+ *      Fine-grained netlink support
+ *      IPv6 support
+ *      Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/*
+ * A policy database (policydb) specifies the 
+ * configuration data for the security policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_POLICYDB_H_
+#define _SEPOL_POLICYDB_POLICYDB_H_
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include <sepol/policydb.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/sidtab.h>
+#include <sys/cdefs.h>
+
+#define ERRMSG_LEN 1024
+
+#define POLICYDB_SUCCESS      0
+#define POLICYDB_ERROR       -1
+#define POLICYDB_UNSUPPORTED -2
+
+__BEGIN_DECLS
+
+/*
+ * A datum type is defined for each kind of symbol 
+ * in the configuration data:  individual permissions, 
+ * common prefixes for access vectors, classes,
+ * users, roles, types, sensitivities, categories, etc.
+ */
+
+/* type set preserves data needed by modules such as *, ~ and attributes */
+typedef struct type_set {
+	ebitmap_t types;
+	ebitmap_t negset;
+#define TYPE_STAR 1
+#define TYPE_COMP 2
+	uint32_t flags;
+} type_set_t;
+
+typedef struct role_set {
+	ebitmap_t roles;
+#define ROLE_STAR 1
+#define ROLE_COMP 2
+	uint32_t flags;
+} role_set_t;
+
+/* Permission attributes */
+typedef struct perm_datum {
+	symtab_datum_t s;
+} perm_datum_t;
+
+/* Attributes of a common prefix for access vectors */
+typedef struct common_datum {
+	symtab_datum_t s;
+	symtab_t permissions;	/* common permissions */
+} common_datum_t;
+
+/* Class attributes */
+typedef struct class_datum {
+	symtab_datum_t s;
+	char *comkey;		/* common name */
+	common_datum_t *comdatum;	/* common datum */
+	symtab_t permissions;	/* class-specific permission symbol table */
+	constraint_node_t *constraints;	/* constraints on class permissions */
+	constraint_node_t *validatetrans;	/* special transition rules */
+/* Options how a new object user and role should be decided */
+#define DEFAULT_SOURCE		1
+#define DEFAULT_TARGET		2
+	char default_user;
+	char default_role;
+	char default_type;
+/* Options how a new object range should be decided */
+#define DEFAULT_SOURCE_LOW	1
+#define DEFAULT_SOURCE_HIGH	2
+#define DEFAULT_SOURCE_LOW_HIGH	3
+#define DEFAULT_TARGET_LOW	4
+#define DEFAULT_TARGET_HIGH	5
+#define DEFAULT_TARGET_LOW_HIGH	6
+	char default_range;
+} class_datum_t;
+
+/* Role attributes */
+typedef struct role_datum {
+	symtab_datum_t s;
+	ebitmap_t dominates;	/* set of roles dominated by this role */
+	type_set_t types;	/* set of authorized types for role */
+	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
+#define ROLE_ROLE 0		/* regular role in kernel policies */
+#define ROLE_ATTRIB 1		/* attribute */
+	uint32_t flavor;
+	ebitmap_t roles;	/* roles with this attribute */
+} role_datum_t;
+
+typedef struct role_trans {
+	uint32_t role;		/* current role */
+	uint32_t type;		/* program executable type, or new object type */
+	uint32_t tclass;	/* process class, or new object class */
+	uint32_t new_role;	/* new role */
+	struct role_trans *next;
+} role_trans_t;
+
+typedef struct role_allow {
+	uint32_t role;		/* current role */
+	uint32_t new_role;	/* new role */
+	struct role_allow *next;
+} role_allow_t;
+
+/* filename_trans rules */
+typedef struct filename_trans {
+	uint32_t stype;
+	uint32_t ttype;
+	uint32_t tclass;
+	char *name;
+	uint32_t otype;
+	struct filename_trans *next;
+} filename_trans_t;
+
+/* Type attributes */
+typedef struct type_datum {
+	symtab_datum_t s;
+	uint32_t primary;	/* primary name? can be set to primary value if below is TYPE_ */
+#define TYPE_TYPE 0		/* regular type or alias in kernel policies */
+#define TYPE_ATTRIB 1		/* attribute */
+#define TYPE_ALIAS 2		/* alias in modular policy */
+	uint32_t flavor;
+	ebitmap_t types;	/* types with this attribute */
+#define TYPE_FLAGS_PERMISSIVE	0x01
+	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
+} type_datum_t;
+
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+#define TYPEDATUM_PROPERTY_ALIAS	0x0004	/* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE	0x0008	/* userspace only */
+
+/* User attributes */
+typedef struct user_datum {
+	symtab_datum_t s;
+	role_set_t roles;	/* set of authorized roles for user */
+	mls_semantic_range_t range;	/* MLS range (min. - max.) for user */
+	mls_semantic_level_t dfltlevel;	/* default login MLS level for user */
+	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	mls_range_t exp_range;     /* expanded range used for validation */
+	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
+} user_datum_t;
+
+/* Sensitivity attributes */
+typedef struct level_datum {
+	mls_level_t *level;	/* sensitivity and associated categories */
+	unsigned char isalias;	/* is this sensitivity an alias for another? */
+	unsigned char defined;
+} level_datum_t;
+
+/* Category attributes */
+typedef struct cat_datum {
+	symtab_datum_t s;
+	unsigned char isalias;	/* is this category an alias for another? */
+} cat_datum_t;
+
+typedef struct range_trans {
+	uint32_t source_type;
+	uint32_t target_type;
+	uint32_t target_class;
+	mls_range_t target_range;
+	struct range_trans *next;
+} range_trans_t;
+
+/* Boolean data type */
+typedef struct cond_bool_datum {
+	symtab_datum_t s;
+	int state;
+#define COND_BOOL_FLAGS_TUNABLE	0x01	/* is this a tunable? */
+	uint32_t flags;
+} cond_bool_datum_t;
+
+struct cond_node;
+
+typedef struct cond_node cond_list_t;
+struct cond_av_list;
+
+typedef struct class_perm_node {
+	uint32_t tclass;
+	uint32_t data;		/* permissions or new type */
+	struct class_perm_node *next;
+} class_perm_node_t;
+
+#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
+#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
+#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
+#define EXTENDED_PERMS_LEN 8
+
+typedef struct av_extended_perms {
+#define AVRULE_XPERMS_IOCTLFUNCTION	0x01
+#define AVRULE_XPERMS_IOCTLDRIVER	0x02
+	uint8_t specified;
+	uint8_t driver;
+	/* 256 bits of permissions */
+	uint32_t perms[EXTENDED_PERMS_LEN];
+} av_extended_perms_t;
+
+typedef struct avrule {
+/* these typedefs are almost exactly the same as those in avtab.h - they are
+ * here because of the need to include neverallow and dontaudit messages */
+#define AVRULE_ALLOWED			0x0001
+#define AVRULE_AUDITALLOW		0x0002
+#define AVRULE_AUDITDENY		0x0004
+#define AVRULE_DONTAUDIT		0x0008
+#define AVRULE_NEVERALLOW		0x0080
+#define AVRULE_AV         (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define AVRULE_TRANSITION		0x0010
+#define AVRULE_MEMBER			0x0020
+#define AVRULE_CHANGE			0x0040
+#define AVRULE_TYPE       (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+#define AVRULE_XPERMS_ALLOWED 		0x0100
+#define AVRULE_XPERMS_AUDITALLOW	0x0200
+#define AVRULE_XPERMS_DONTAUDIT		0x0400
+#define AVRULE_XPERMS_NEVERALLOW	0x0800
+#define AVRULE_XPERMS	(AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
+				AVRULE_XPERMS_DONTAUDIT | AVRULE_XPERMS_NEVERALLOW)
+	uint32_t specified;
+#define RULE_SELF 1
+	uint32_t flags;
+	type_set_t stypes;
+	type_set_t ttypes;
+	class_perm_node_t *perms;
+	av_extended_perms_t *xperms;
+	unsigned long line;	/* line number from policy.conf where
+				 * this rule originated  */
+	/* source file name and line number (e.g. .te file) */
+	char *source_filename;
+	unsigned long source_line;
+	struct avrule *next;
+} avrule_t;
+
+typedef struct role_trans_rule {
+	role_set_t roles;	/* current role */
+	type_set_t types;	/* program executable type, or new object type */
+	ebitmap_t classes;	/* process class, or new object class */
+	uint32_t new_role;	/* new role */
+	struct role_trans_rule *next;
+} role_trans_rule_t;
+
+typedef struct role_allow_rule {
+	role_set_t roles;	/* current role */
+	role_set_t new_roles;	/* new roles */
+	struct role_allow_rule *next;
+} role_allow_rule_t;
+
+typedef struct filename_trans_rule {
+	type_set_t stypes;
+	type_set_t ttypes;
+	uint32_t tclass;
+	char *name;
+	uint32_t otype;	/* new type */
+	struct filename_trans_rule *next;
+} filename_trans_rule_t;
+
+typedef struct range_trans_rule {
+	type_set_t stypes;
+	type_set_t ttypes;
+	ebitmap_t tclasses;
+	mls_semantic_range_t trange;
+	struct range_trans_rule *next;
+} range_trans_rule_t;
+
+/*
+ * The configuration data includes security contexts for 
+ * initial SIDs, unlabeled file systems, TCP and UDP port numbers, 
+ * network interfaces, and nodes.  This structure stores the
+ * relevant data for one such entry.  Entries of the same kind
+ * (e.g. all initial SIDs) are linked together into a list.
+ */
+typedef struct ocontext {
+	union {
+		char *name;	/* name of initial SID, fs, netif, fstype, path */
+		struct {
+			uint8_t protocol;
+			uint16_t low_port;
+			uint16_t high_port;
+		} port;		/* TCP or UDP port information */
+		struct {
+			uint32_t addr; /* network order */
+			uint32_t mask; /* network order */
+		} node;		/* node information */
+		struct {
+			uint32_t addr[4]; /* network order */
+			uint32_t mask[4]; /* network order */
+		} node6;	/* IPv6 node information */
+		uint32_t device;
+		uint16_t pirq;
+		struct {
+			uint64_t low_iomem;
+			uint64_t high_iomem;
+		} iomem;
+		struct {
+			uint32_t low_ioport;
+			uint32_t high_ioport;
+		} ioport;
+	} u;
+	union {
+		uint32_t sclass;	/* security class for genfs */
+		uint32_t behavior;	/* labeling behavior for fs_use */
+	} v;
+	context_struct_t context[2];	/* security context(s) */
+	sepol_security_id_t sid[2];	/* SID(s) */
+	struct ocontext *next;
+} ocontext_t;
+
+typedef struct genfs {
+	char *fstype;
+	struct ocontext *head;
+	struct genfs *next;
+} genfs_t;
+
+/* symbol table array indices */
+#define SYM_COMMONS 0
+#define SYM_CLASSES 1
+#define SYM_ROLES   2
+#define SYM_TYPES   3
+#define SYM_USERS   4
+#define SYM_BOOLS   5
+#define SYM_LEVELS  6
+#define SYM_CATS    7
+#define SYM_NUM     8
+
+/* object context array indices */
+#define OCON_ISID  0		/* initial SIDs */
+#define OCON_FS    1		/* unlabeled file systems */
+#define OCON_PORT  2		/* TCP and UDP port numbers */
+#define OCON_NETIF 3		/* network interfaces */
+#define OCON_NODE  4		/* nodes */
+#define OCON_FSUSE 5		/* fs_use */
+#define OCON_NODE6 6		/* IPv6 nodes */
+#define OCON_GENFS 7            /* needed for ocontext_supported */
+
+/* object context array indices for Xen */
+#define OCON_XEN_ISID  	    0    /* initial SIDs */
+#define OCON_XEN_PIRQ       1    /* physical irqs */
+#define OCON_XEN_IOPORT     2    /* io ports */
+#define OCON_XEN_IOMEM	    3    /* io memory */
+#define OCON_XEN_PCIDEVICE  4    /* pci devices */
+#define OCON_XEN_DEVICETREE 5    /* device tree node */
+
+/* OCON_NUM needs to be the largest index in any platform's ocontext array */
+#define OCON_NUM   7
+
+/* section: module information */
+
+/* scope_index_t holds all of the symbols that are in scope in a
+ * particular situation.  The bitmaps are indices (and thus must
+ * subtract one) into the global policydb->scope array. */
+typedef struct scope_index {
+	ebitmap_t scope[SYM_NUM];
+#define p_classes_scope scope[SYM_CLASSES]
+#define p_roles_scope scope[SYM_ROLES]
+#define p_types_scope scope[SYM_TYPES]
+#define p_users_scope scope[SYM_USERS]
+#define p_bools_scope scope[SYM_BOOLS]
+#define p_sens_scope scope[SYM_LEVELS]
+#define p_cat_scope scope[SYM_CATS]
+
+	/* this array maps from class->value to the permissions within
+	 * scope.  if bit (perm->value - 1) is set in map
+	 * class_perms_map[class->value - 1] then that permission is
+	 * enabled for this class within this decl.  */
+	ebitmap_t *class_perms_map;
+	/* total number of classes in class_perms_map array */
+	uint32_t class_perms_len;
+} scope_index_t;
+
+/* a list of declarations for a particular avrule_decl */
+
+/* These two structs declare a block of policy that has TE and RBAC
+ * statements and declarations.  The root block (the global policy)
+ * can never have an ELSE branch. */
+typedef struct avrule_decl {
+	uint32_t decl_id;
+	uint32_t enabled;	/* whether this block is enabled */
+
+	cond_list_t *cond_list;
+	avrule_t *avrules;
+	role_trans_rule_t *role_tr_rules;
+	role_allow_rule_t *role_allow_rules;
+	range_trans_rule_t *range_tr_rules;
+	scope_index_t required;	/* symbols needed to activate this block */
+	scope_index_t declared;	/* symbols declared within this block */
+
+	/* type transition rules with a 'name' component */
+	filename_trans_rule_t *filename_trans_rules;
+
+	/* for additive statements (type attribute, roles, and users) */
+	symtab_t symtab[SYM_NUM];
+
+	/* In a linked module this will contain the name of the module
+	 * from which this avrule_decl originated. */
+	char *module_name;
+
+	struct avrule_decl *next;
+} avrule_decl_t;
+
+typedef struct avrule_block {
+	avrule_decl_t *branch_list;
+	avrule_decl_t *enabled;	/* pointer to which branch is enabled.  this is
+				   used in linking and never written to disk */
+#define AVRULE_OPTIONAL 1
+	uint32_t flags;		/* any flags for this block, currently just optional */
+	struct avrule_block *next;
+} avrule_block_t;
+
+/* Every identifier has its own scope datum.  The datum describes if
+ * the item is to be included into the final policy during
+ * expansion. */
+typedef struct scope_datum {
+/* Required for this decl */
+#define SCOPE_REQ  1
+/* Declared in this decl */
+#define SCOPE_DECL 2
+	uint32_t scope;
+	uint32_t *decl_ids;
+	uint32_t decl_ids_len;
+	/* decl_ids is a list of avrule_decl's that declare/require
+	 * this symbol.  If scope==SCOPE_DECL then this is a list of
+	 * declarations.  If the symbol may only be declared once
+	 * (types, bools) then decl_ids_len will be exactly 1.  For
+	 * implicitly declared things (roles, users) then decl_ids_len
+	 * will be at least 1. */
+} scope_datum_t;
+
+/* The policy database */
+typedef struct policydb {
+#define POLICY_KERN SEPOL_POLICY_KERN
+#define POLICY_BASE SEPOL_POLICY_BASE
+#define POLICY_MOD SEPOL_POLICY_MOD
+	uint32_t policy_type;
+	char *name;
+	char *version;
+	int  target_platform;
+
+	/* Set when the policydb is modified such that writing is unsupported */
+	int unsupported_format;
+
+	/* Whether this policydb is mls, should always be set */
+	int mls;
+
+	/* symbol tables */
+	symtab_t symtab[SYM_NUM];
+#define p_commons symtab[SYM_COMMONS]
+#define p_classes symtab[SYM_CLASSES]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
+
+	/* symbol names indexed by (value - 1) */
+	char **sym_val_to_name[SYM_NUM];
+#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
+#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
+#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
+#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
+#define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
+#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
+#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+
+	/* class, role, and user attributes indexed by (value - 1) */
+	class_datum_t **class_val_to_struct;
+	role_datum_t **role_val_to_struct;
+	user_datum_t **user_val_to_struct;
+	type_datum_t **type_val_to_struct;
+
+	/* module stuff section -- used in parsing and for modules */
+
+	/* keep track of the scope for every identifier.  these are
+	 * hash tables, where the key is the identifier name and value
+	 * a scope_datum_t.  as a convenience, one may use the
+	 * p_*_macros (cf. struct scope_index_t declaration). */
+	symtab_t scope[SYM_NUM];
+
+	/* module rule storage */
+	avrule_block_t *global;
+	/* avrule_decl index used for link/expand */
+	avrule_decl_t **decl_val_to_struct;
+
+	/* compiled storage of rules - use for the kernel policy */
+
+	/* type enforcement access vectors and transitions */
+	avtab_t te_avtab;
+
+	/* bools indexed by (value - 1) */
+	cond_bool_datum_t **bool_val_to_struct;
+	/* type enforcement conditional access vectors and transitions */
+	avtab_t te_cond_avtab;
+	/* linked list indexing te_cond_avtab by conditional */
+	cond_list_t *cond_list;
+
+	/* role transitions */
+	role_trans_t *role_tr;
+
+	/* type transition rules with a 'name' component */
+	filename_trans_t *filename_trans;
+
+	/* role allows */
+	role_allow_t *role_allow;
+
+	/* security contexts of initial SIDs, unlabeled file systems,
+	   TCP or UDP port numbers, network interfaces and nodes */
+	ocontext_t *ocontexts[OCON_NUM];
+
+	/* security contexts for files in filesystems that cannot support
+	   a persistent label mapping or use another 
+	   fixed labeling behavior. */
+	genfs_t *genfs;
+
+	/* range transitions */
+	range_trans_t *range_tr;
+
+	ebitmap_t *type_attr_map;
+
+	ebitmap_t *attr_type_map;	/* not saved in the binary policy */
+
+	ebitmap_t policycaps;
+
+	/* this bitmap is referenced by type NOT the typical type-1 used in other
+	   bitmaps.  Someday the 0 bit may be used for global permissive */
+	ebitmap_t permissive_map;
+
+	unsigned policyvers;
+
+	unsigned handle_unknown;
+} policydb_t;
+
+struct sepol_policydb {
+	struct policydb p;
+};
+
+extern int policydb_init(policydb_t * p);
+
+extern int policydb_from_image(sepol_handle_t * handle,
+			       void *data, size_t len, policydb_t * policydb);
+
+extern int policydb_to_image(sepol_handle_t * handle,
+			     policydb_t * policydb, void **newdata,
+			     size_t * newlen);
+
+extern int policydb_index_classes(policydb_t * p);
+
+extern int policydb_index_bools(policydb_t * p);
+
+extern int policydb_index_others(sepol_handle_t * handle, policydb_t * p,
+				 unsigned int verbose);
+
+extern int policydb_reindex_users(policydb_t * p);
+
+extern void policydb_destroy(policydb_t * p);
+
+extern int policydb_load_isids(policydb_t * p, sidtab_t * s);
+
+/* Deprecated */
+extern int policydb_context_isvalid(const policydb_t * p,
+				    const context_struct_t * c);
+
+extern void symtabs_destroy(symtab_t * symtab);
+extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
+typedef void (*hashtab_destroy_func_t) (hashtab_key_t k, hashtab_datum_t d,
+					void *args);
+extern hashtab_destroy_func_t get_symtab_destroy_func(int sym_num);
+
+extern void class_perm_node_init(class_perm_node_t * x);
+extern void type_set_init(type_set_t * x);
+extern void type_set_destroy(type_set_t * x);
+extern int type_set_cpy(type_set_t * dst, type_set_t * src);
+extern int type_set_or_eq(type_set_t * dst, type_set_t * other);
+extern void role_set_init(role_set_t * x);
+extern void role_set_destroy(role_set_t * x);
+extern void avrule_init(avrule_t * x);
+extern void avrule_destroy(avrule_t * x);
+extern void avrule_list_destroy(avrule_t * x);
+extern void role_trans_rule_init(role_trans_rule_t * x);
+extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
+extern void filename_trans_rule_init(filename_trans_rule_t * x);
+extern void filename_trans_rule_list_destroy(filename_trans_rule_t * x);
+
+extern void role_datum_init(role_datum_t * x);
+extern void role_datum_destroy(role_datum_t * x);
+extern void role_allow_rule_init(role_allow_rule_t * x);
+extern void role_allow_rule_destroy(role_allow_rule_t * x);
+extern void role_allow_rule_list_destroy(role_allow_rule_t * x);
+extern void range_trans_rule_init(range_trans_rule_t *x);
+extern void range_trans_rule_destroy(range_trans_rule_t *x);
+extern void range_trans_rule_list_destroy(range_trans_rule_t *x);
+extern void type_datum_init(type_datum_t * x);
+extern void type_datum_destroy(type_datum_t * x);
+extern void user_datum_init(user_datum_t * x);
+extern void user_datum_destroy(user_datum_t * x);
+extern void level_datum_init(level_datum_t * x);
+extern void level_datum_destroy(level_datum_t * x);
+extern void cat_datum_init(cat_datum_t * x);
+extern void cat_datum_destroy(cat_datum_t * x);
+extern int check_assertion(policydb_t *p, avrule_t *avrule);
+extern int check_assertions(sepol_handle_t * handle,
+			    policydb_t * p, avrule_t * avrules);
+
+extern int symtab_insert(policydb_t * x, uint32_t sym,
+			 hashtab_key_t key, hashtab_datum_t datum,
+			 uint32_t scope, uint32_t avrule_decl_id,
+			 uint32_t * value);
+
+/* A policy "file" may be a memory region referenced by a (data, len) pair
+   or a file referenced by a FILE pointer. */
+typedef struct policy_file {
+#define PF_USE_MEMORY  0
+#define PF_USE_STDIO   1
+#define PF_LEN         2	/* total up length in len field */
+	unsigned type;
+	char *data;
+	size_t len;
+	size_t size;
+	FILE *fp;
+	struct sepol_handle *handle;
+} policy_file_t;
+
+struct sepol_policy_file {
+	struct policy_file pf;
+};
+
+extern void policy_file_init(policy_file_t * x);
+
+extern int policydb_read(policydb_t * p, struct policy_file *fp,
+			 unsigned int verbose);
+extern int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+			    struct policy_file *fp);
+
+extern int policydb_write(struct policydb *p, struct policy_file *pf);
+extern int policydb_set_target_platform(policydb_t *p, int platform);
+
+#define PERM_SYMTAB_SIZE 32
+
+/* Identify specific policy version changes */
+#define POLICYDB_VERSION_BASE		15
+#define POLICYDB_VERSION_BOOL		16
+#define POLICYDB_VERSION_IPV6		17
+#define POLICYDB_VERSION_NLCLASS	18
+#define POLICYDB_VERSION_VALIDATETRANS	19
+#define POLICYDB_VERSION_MLS		19
+#define POLICYDB_VERSION_AVTAB		20
+#define POLICYDB_VERSION_RANGETRANS	21
+#define POLICYDB_VERSION_POLCAP		22
+#define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
+#define POLICYDB_VERSION_FILENAME_TRANS	25
+#define POLICYDB_VERSION_ROLETRANS	26
+#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS	27
+#define POLICYDB_VERSION_DEFAULT_TYPE	28
+#define POLICYDB_VERSION_CONSTRAINT_NAMES	29
+#define POLICYDB_VERSION_XEN_DEVICETREE		30 /* Xen-specific */
+#define POLICYDB_VERSION_XPERMS_IOCTL	30 /* Linux-specific */
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_XPERMS_IOCTL
+
+/* Module versions and specific changes*/
+#define MOD_POLICYDB_VERSION_BASE		4
+#define MOD_POLICYDB_VERSION_VALIDATETRANS	5
+#define MOD_POLICYDB_VERSION_MLS		5
+#define MOD_POLICYDB_VERSION_RANGETRANS 	6
+#define MOD_POLICYDB_VERSION_MLS_USERS		6
+#define MOD_POLICYDB_VERSION_POLCAP		7
+#define MOD_POLICYDB_VERSION_PERMISSIVE		8
+#define MOD_POLICYDB_VERSION_BOUNDARY		9
+#define MOD_POLICYDB_VERSION_BOUNDARY_ALIAS	10
+#define MOD_POLICYDB_VERSION_FILENAME_TRANS	11
+#define MOD_POLICYDB_VERSION_ROLETRANS		12
+#define MOD_POLICYDB_VERSION_ROLEATTRIB		13
+#define MOD_POLICYDB_VERSION_TUNABLE_SEP	14
+#define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS	15
+#define MOD_POLICYDB_VERSION_DEFAULT_TYPE	16
+#define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES  17
+
+#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES
+
+#define POLICYDB_CONFIG_MLS    1
+
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
+/* the config flags related to unknown classes/perms are bits 2 and 3 */
+#define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
+#define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
+#define ALLOW_UNKNOWN 	SEPOL_ALLOW_UNKNOWN
+
+#define POLICYDB_CONFIG_UNKNOWN_MASK	(DENY_UNKNOWN | REJECT_UNKNOWN | ALLOW_UNKNOWN)
+
+#define OBJECT_R "object_r"
+#define OBJECT_R_VAL 1
+
+#define POLICYDB_MAGIC SELINUX_MAGIC
+#define POLICYDB_STRING "SE Linux"
+#define POLICYDB_XEN_STRING "XenFlask"
+#define POLICYDB_STRING_MAX_LENGTH 32
+#define POLICYDB_MOD_MAGIC SELINUX_MOD_MAGIC
+#define POLICYDB_MOD_STRING "SE Linux Module"
+
+__END_DECLS
+#endif				/* _POLICYDB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h
new file mode 100644
index 0000000..8a5dc9a
--- /dev/null
+++ b/libsepol/include/sepol/policydb/services.h
@@ -0,0 +1,234 @@
+
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+
+#ifndef _SEPOL_POLICYDB_SERVICES_H_
+#define _SEPOL_POLICYDB_SERVICES_H_
+
+/*
+ * Security server interface.
+ */
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Set the policydb and sidtab structures to be used by
+   the service functions.  If not set, then these default
+   to private structures within libsepol that can only be
+   initialized and accessed via the service functions themselves.
+   Setting the structures explicitly allows a program to directly
+   manipulate them, e.g. checkpolicy populates the structures directly
+   from a source policy rather than from a binary policy. */
+extern int sepol_set_policydb(policydb_t * p);
+extern int sepol_set_sidtab(sidtab_t * s);
+
+/* Modify a policydb for boolean settings. */
+int sepol_genbools_policydb(policydb_t * policydb, const char *booleans);
+
+/* Modify a policydb for user settings. */
+int sepol_genusers_policydb(policydb_t * policydb, const char *usersdir);
+
+/* Load the security policy. This initializes the policydb
+   and sidtab based on the provided binary policy. */
+extern int sepol_load_policy(void *data, size_t len);
+
+/*
+ * Compute access vectors based on a SID pair for
+ * the permissions in a particular class.
+ */
+extern int sepol_compute_av(sepol_security_id_t ssid,	/* IN */
+			    sepol_security_id_t tsid,	/* IN */
+			    sepol_security_class_t tclass,	/* IN */
+			    sepol_access_vector_t requested,	/* IN */
+			    struct sepol_av_decision *avd);	/* OUT */
+
+/* Same as above, but also return the reason(s) for any
+   denials of the requested permissions. */
+#define SEPOL_COMPUTEAV_TE   1
+#define SEPOL_COMPUTEAV_CONS 2
+#define SEPOL_COMPUTEAV_RBAC 4
+extern int sepol_compute_av_reason(sepol_security_id_t ssid,
+				   sepol_security_id_t tsid,
+				   sepol_security_class_t tclass,
+				   sepol_access_vector_t requested,
+				   struct sepol_av_decision *avd,
+				   unsigned int *reason);
+
+/*
+ * Same as above, but also returns the constraint expression calculations
+ * whether allowed or denied in a buffer. This buffer is allocated by
+ * this call and must be free'd by the caller using free(3). The contraint
+ * buffer will contain any constraints in infix notation.
+ * If the SHOW_GRANTED flag is set it will show granted and denied
+ * constraints. The default is to show only denied constraints.
+ */
+#define SHOW_GRANTED 1
+extern int sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
+				   sepol_security_id_t tsid,
+				   sepol_security_class_t tclass,
+				   sepol_access_vector_t requested,
+				   struct sepol_av_decision *avd,
+				   unsigned int *reason,
+				   char **reason_buf,
+				   unsigned int flags);
+
+/*
+ * Returns the mls/validatetrans constraint expression calculations in
+ * a buffer that must be free'd by the caller using free(3).
+ * If the SHOW_GRANTED flag is set it will show granted and denied
+ * mls/validatetrans (the default is to show only those denied).
+ */
+extern int sepol_validate_transition_reason_buffer(sepol_security_id_t oldsid,
+					sepol_security_id_t newsid,
+					sepol_security_id_t tasksid,
+					sepol_security_class_t tclass,
+					char **reason_buf,
+					unsigned int flags);
+
+/*
+ * Return a class ID associated with the class string representation
+ * specified by `class_name'.
+ */
+extern int sepol_string_to_security_class(const char *class_name,
+					sepol_security_class_t  *tclass);
+
+/*
+ * Return a permission av bit associated with tclass and the string
+ * representation of the `perm_name'.
+ */
+extern int sepol_string_to_av_perm(sepol_security_class_t tclass,
+					const char *perm_name,
+					sepol_access_vector_t *av);
+
+/*
+ * Compute a SID to use for labeling a new object in the 
+ * class `tclass' based on a SID pair.  
+ */
+extern int sepol_transition_sid(sepol_security_id_t ssid,	/* IN */
+				sepol_security_id_t tsid,	/* IN */
+				sepol_security_class_t tclass,	/* IN */
+				sepol_security_id_t * out_sid);	/* OUT */
+
+/*
+ * Compute a SID to use when selecting a member of a 
+ * polyinstantiated object of class `tclass' based on 
+ * a SID pair.
+ */
+extern int sepol_member_sid(sepol_security_id_t ssid,	/* IN */
+			    sepol_security_id_t tsid,	/* IN */
+			    sepol_security_class_t tclass,	/* IN */
+			    sepol_security_id_t * out_sid);	/* OUT */
+
+/*
+ * Compute a SID to use for relabeling an object in the 
+ * class `tclass' based on a SID pair.  
+ */
+extern int sepol_change_sid(sepol_security_id_t ssid,	/* IN */
+			    sepol_security_id_t tsid,	/* IN */
+			    sepol_security_class_t tclass,	/* IN */
+			    sepol_security_id_t * out_sid);	/* OUT */
+
+/*
+ * Write the security context string representation of 
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size.  Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+extern int sepol_sid_to_context(sepol_security_id_t sid,	/* IN */
+				sepol_security_context_t * scontext,	/* OUT */
+				size_t * scontext_len);	/* OUT */
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+extern int sepol_context_to_sid(const sepol_security_context_t scontext,	/* IN */
+				size_t scontext_len,	/* IN */
+				sepol_security_id_t * out_sid);	/* OUT */
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated 
+ * array containing the set of SIDs.  Set `*nel' to the
+ * number of elements in the array.
+ */
+extern int sepol_get_user_sids(sepol_security_id_t callsid,
+			       char *username,
+			       sepol_security_id_t ** sids, uint32_t * nel);
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'.  The `fs_sid' SID is returned for 
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+extern int sepol_fs_sid(char *dev,	/* IN */
+			sepol_security_id_t * fs_sid,	/* OUT  */
+			sepol_security_id_t * file_sid);	/* OUT */
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+extern int sepol_port_sid(uint16_t domain,
+			  uint16_t type,
+			  uint8_t protocol,
+			  uint16_t port, sepol_security_id_t * out_sid);
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'.  The `if_sid' SID is returned for 
+ * the interface and the `msg_sid' SID is returned as
+ * the default SID for messages received on the
+ * interface.
+ */
+extern int sepol_netif_sid(char *name,
+			   sepol_security_id_t * if_sid,
+			   sepol_security_id_t * msg_sid);
+
+/*
+ * Return the SID of the node specified by the address
+ * `addr' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+extern int sepol_node_sid(uint16_t domain,
+			  void *addr,
+			  size_t addrlen, sepol_security_id_t * out_sid);
+
+/*
+ * Return a value indicating how to handle labeling for the
+ * the specified filesystem type, and optionally return a SID
+ * for the filesystem object.  
+ */
+#define SECURITY_FS_USE_XATTR 1	/* use xattr */
+#define SECURITY_FS_USE_TRANS 2	/* use transition SIDs, e.g. devpts/tmpfs */
+#define SECURITY_FS_USE_TASK  3	/* use task SIDs, e.g. pipefs/sockfs */
+#define SECURITY_FS_USE_GENFS 4	/* use the genfs support */
+#define SECURITY_FS_USE_NONE  5	/* no labeling support */
+extern int sepol_fs_use(const char *fstype,	/* IN */
+			unsigned int *behavior,	/* OUT */
+			sepol_security_id_t * sid);	/* OUT  */
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+extern int sepol_genfs_sid(const char *fstype,	/* IN */
+			   const char *name,	/* IN */
+			   sepol_security_class_t sclass,	/* IN */
+			   sepol_security_id_t * sid);	/* OUT  */
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/sidtab.h b/libsepol/include/sepol/policydb/sidtab.h
new file mode 100644
index 0000000..4b93567
--- /dev/null
+++ b/libsepol/include/sepol/policydb/sidtab.h
@@ -0,0 +1,75 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ */
+
+#ifndef _SEPOL_POLICYDB_SIDTAB_H_
+#define _SEPOL_POLICYDB_SIDTAB_H_
+
+#include <sepol/policydb/context.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct sidtab_node {
+	sepol_security_id_t sid;	/* security identifier */
+	context_struct_t context;	/* security context structure */
+	struct sidtab_node *next;
+} sidtab_node_t;
+
+typedef struct sidtab_node *sidtab_ptr_t;
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+typedef struct {
+	sidtab_ptr_t *htable;
+	unsigned int nel;	/* number of elements */
+	unsigned int next_sid;	/* next SID to allocate */
+	unsigned char shutdown;
+} sidtab_t;
+
+extern int sepol_sidtab_init(sidtab_t * s);
+
+extern int sepol_sidtab_insert(sidtab_t * s,
+			       sepol_security_id_t sid,
+			       context_struct_t * context);
+
+extern context_struct_t *sepol_sidtab_search(sidtab_t * s,
+					     sepol_security_id_t sid);
+
+extern int sepol_sidtab_map(sidtab_t * s,
+			    int (*apply) (sepol_security_id_t sid,
+					  context_struct_t * context,
+					  void *args), void *args);
+
+extern void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+					     int (*apply) (sepol_security_id_t
+							   s,
+							   context_struct_t *
+							   context, void *args),
+					     void *args);
+
+extern int sepol_sidtab_context_to_sid(sidtab_t * s,	/* IN */
+				       context_struct_t * context,	/* IN */
+				       sepol_security_id_t * sid);	/* OUT */
+
+extern void sepol_sidtab_hash_eval(sidtab_t * h, char *tag);
+
+extern void sepol_sidtab_destroy(sidtab_t * s);
+
+extern void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src);
+
+extern void sepol_sidtab_shutdown(sidtab_t * s);
+
+__END_DECLS
+#endif				/* _SIDTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/symtab.h b/libsepol/include/sepol/policydb/symtab.h
new file mode 100644
index 0000000..e0da337
--- /dev/null
+++ b/libsepol/include/sepol/policydb/symtab.h
@@ -0,0 +1,43 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A symbol table (symtab) maintains associations between symbol
+ * strings and datum values.  The type of the datum values
+ * is arbitrary.  The symbol table type is implemented
+ * using the hash table type (hashtab).
+ */
+
+#ifndef _SEPOL_POLICYDB_SYMTAB_H_
+#define _SEPOL_POLICYDB_SYMTAB_H_
+
+#include <sepol/policydb/hashtab.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* The symtab_datum struct stores the common information for
+ * all symtab datums. It should the first element in every
+ * struct that will be used in a symtab to allow the specific
+ * datum types to be freely cast to this type.
+ *
+ * The values start at 1 - 0 is never a valid value.
+ */
+typedef struct symtab_datum {
+	uint32_t value;
+} symtab_datum_t;
+
+typedef struct {
+	hashtab_t table;	/* hash table (keyed on a string) */
+	uint32_t nprim;		/* number of primary names in table */
+} symtab_t;
+
+extern int symtab_init(symtab_t *, unsigned int size);
+extern void symtab_destroy(symtab_t *);
+
+__END_DECLS
+#endif				/* _SYMTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/util.h b/libsepol/include/sepol/policydb/util.h
new file mode 100644
index 0000000..fa12661
--- /dev/null
+++ b/libsepol/include/sepol/policydb/util.h
@@ -0,0 +1,44 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * 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
+ */
+
+#ifndef __SEPOL_UTIL_H__
+#define __SEPOL_UTIL_H__
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
+
+extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+				sepol_access_vector_t av);
+
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms);
+
+/*
+ * The tokenize function may be used to
+ * replace sscanf
+ */
+extern int tokenize(char *line_buf, char delim, int num_args, ...);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/port_record.h b/libsepol/include/sepol/port_record.h
new file mode 100644
index 0000000..c07d1fa
--- /dev/null
+++ b/libsepol/include/sepol/port_record.h
@@ -0,0 +1,71 @@
+#ifndef _SEPOL_PORT_RECORD_H_
+#define _SEPOL_PORT_RECORD_H_
+
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_port;
+struct sepol_port_key;
+typedef struct sepol_port sepol_port_t;
+typedef struct sepol_port_key sepol_port_key_t;
+
+#define SEPOL_PROTO_UDP 0
+#define SEPOL_PROTO_TCP 1
+#define SEPOL_PROTO_DCCP 2
+
+/* Key */
+extern int sepol_port_compare(const sepol_port_t * port,
+			      const sepol_port_key_t * key);
+
+extern int sepol_port_compare2(const sepol_port_t * port,
+			       const sepol_port_t * port2);
+
+extern int sepol_port_key_create(sepol_handle_t * handle,
+				 int low, int high, int proto,
+				 sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_unpack(const sepol_port_key_t * key,
+				  int *low, int *high, int *proto);
+
+extern int sepol_port_key_extract(sepol_handle_t * handle,
+				  const sepol_port_t * port,
+				  sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_free(sepol_port_key_t * key);
+
+/* Protocol */
+extern int sepol_port_get_proto(const sepol_port_t * port);
+
+extern void sepol_port_set_proto(sepol_port_t * port, int proto);
+
+extern const char *sepol_port_get_proto_str(int proto);
+
+/* Port */
+extern int sepol_port_get_low(const sepol_port_t * port);
+
+extern int sepol_port_get_high(const sepol_port_t * port);
+
+extern void sepol_port_set_port(sepol_port_t * port, int port_num);
+
+extern void sepol_port_set_range(sepol_port_t * port, int low, int high);
+
+/* Context */
+extern sepol_context_t *sepol_port_get_con(const sepol_port_t * port);
+
+extern int sepol_port_set_con(sepol_handle_t * handle,
+			      sepol_port_t * port, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port_ptr);
+
+extern int sepol_port_clone(sepol_handle_t * handle,
+			    const sepol_port_t * port,
+			    sepol_port_t ** port_ptr);
+
+extern void sepol_port_free(sepol_port_t * port);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/ports.h b/libsepol/include/sepol/ports.h
new file mode 100644
index 0000000..b4622ba
--- /dev/null
+++ b/libsepol/include/sepol/ports.h
@@ -0,0 +1,44 @@
+#ifndef _SEPOL_PORTS_H_
+#define _SEPOL_PORTS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/port_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle,
+			    const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a port exists */
+extern int sepol_port_exists(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     const sepol_port_key_t * key, int *response);
+
+/* Query a port - returns the port, or NULL if not found */
+extern int sepol_port_query(sepol_handle_t * handle,
+			    const sepol_policydb_t * policydb,
+			    const sepol_port_key_t * key,
+			    sepol_port_t ** response);
+
+/* Modify a port, or add it, if the key is not found */
+extern int sepol_port_modify(sepol_handle_t * handle,
+			     sepol_policydb_t * policydb,
+			     const sepol_port_key_t * key,
+			     const sepol_port_t * data);
+
+/* Iterate the ports 
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_port_iterate(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      int (*fn) (const sepol_port_t * port,
+					 void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/roles.h b/libsepol/include/sepol/roles.h
new file mode 100644
index 0000000..89b3af2
--- /dev/null
+++ b/libsepol/include/sepol/roles.h
@@ -0,0 +1,15 @@
+#ifndef _SEPOL_ROLES_H_
+#define _SEPOL_ROLES_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int sepol_role_exists(const sepol_policydb_t * policydb,
+			     const char *role, int *response);
+
+extern int sepol_role_list(const sepol_policydb_t * policydb,
+			   char ***roles, unsigned int *nroles);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/sepol.h b/libsepol/include/sepol/sepol.h
new file mode 100644
index 0000000..00a2129
--- /dev/null
+++ b/libsepol/include/sepol/sepol.h
@@ -0,0 +1,32 @@
+#ifndef _SEPOL_H_
+#define _SEPOL_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#include <sepol/user_record.h>
+#include <sepol/context_record.h>
+#include <sepol/iface_record.h>
+#include <sepol/port_record.h>
+#include <sepol/boolean_record.h>
+#include <sepol/node_record.h>
+
+#include <sepol/booleans.h>
+#include <sepol/interfaces.h>
+#include <sepol/ports.h>
+#include <sepol/nodes.h>
+#include <sepol/users.h>
+#include <sepol/handle.h>
+#include <sepol/debug.h>
+#include <sepol/policydb.h>
+#include <sepol/module.h>
+#include <sepol/context.h>
+
+/* Set internal policydb from a file for subsequent service calls. */
+extern int sepol_set_policydb_from_file(FILE * fp);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/user_record.h b/libsepol/include/sepol/user_record.h
new file mode 100644
index 0000000..9a39526
--- /dev/null
+++ b/libsepol/include/sepol/user_record.h
@@ -0,0 +1,80 @@
+#ifndef _SEPOL_USER_RECORD_H_
+#define _SEPOL_USER_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_user;
+struct sepol_user_key;
+typedef struct sepol_user sepol_user_t;
+typedef struct sepol_user_key sepol_user_key_t;
+
+/* Key */
+extern int sepol_user_key_create(sepol_handle_t * handle,
+				 const char *name, sepol_user_key_t ** key);
+
+extern void sepol_user_key_unpack(const sepol_user_key_t * key,
+				  const char **name);
+
+extern int sepol_user_key_extract(sepol_handle_t * handle,
+				  const sepol_user_t * user,
+				  sepol_user_key_t ** key_ptr);
+
+extern void sepol_user_key_free(sepol_user_key_t * key);
+
+extern int sepol_user_compare(const sepol_user_t * user,
+			      const sepol_user_key_t * key);
+
+extern int sepol_user_compare2(const sepol_user_t * user,
+			       const sepol_user_t * user2);
+
+/* Name */
+extern const char *sepol_user_get_name(const sepol_user_t * user);
+
+extern int sepol_user_set_name(sepol_handle_t * handle,
+			       sepol_user_t * user, const char *name);
+
+/* MLS */
+extern const char *sepol_user_get_mlslevel(const sepol_user_t * user);
+
+extern int sepol_user_set_mlslevel(sepol_handle_t * handle,
+				   sepol_user_t * user, const char *mls_level);
+
+extern const char *sepol_user_get_mlsrange(const sepol_user_t * user);
+
+extern int sepol_user_set_mlsrange(sepol_handle_t * handle,
+				   sepol_user_t * user, const char *mls_range);
+
+/* Role management */
+extern int sepol_user_get_num_roles(const sepol_user_t * user);
+
+extern int sepol_user_add_role(sepol_handle_t * handle,
+			       sepol_user_t * user, const char *role);
+
+extern void sepol_user_del_role(sepol_user_t * user, const char *role);
+
+extern int sepol_user_has_role(const sepol_user_t * user, const char *role);
+
+extern int sepol_user_get_roles(sepol_handle_t * handle,
+				const sepol_user_t * user,
+				const char ***roles_arr,
+				unsigned int *num_roles);
+
+extern int sepol_user_set_roles(sepol_handle_t * handle,
+				sepol_user_t * user,
+				const char **roles_arr, unsigned int num_roles);
+
+/* Create/Clone/Destroy */
+extern int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr);
+
+extern int sepol_user_clone(sepol_handle_t * handle,
+			    const sepol_user_t * user,
+			    sepol_user_t ** user_ptr);
+
+extern void sepol_user_free(sepol_user_t * user);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/users.h b/libsepol/include/sepol/users.h
new file mode 100644
index 0000000..0e0f76e
--- /dev/null
+++ b/libsepol/include/sepol/users.h
@@ -0,0 +1,61 @@
+#ifndef _SEPOL_USERS_H_
+#define _SEPOL_USERS_H_
+
+#include <sepol/policydb.h>
+#include <sepol/user_record.h>
+#include <sepol/handle.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*---------compatibility------------*/
+
+/* Given an existing binary policy (starting at 'data with length 'len')
+   and user configurations living in 'usersdir', generate a new binary
+   policy for the new user configurations.  Sets '*newdata' and '*newlen'
+   to refer to the new binary policy image. */
+extern int sepol_genusers(void *data, size_t len,
+			  const char *usersdir,
+			  void **newdata, size_t * newlen);
+
+/* Enable or disable deletion of users by sepol_genusers(3) when
+   a user in original binary policy image is not defined by the
+   new user configurations.  Defaults to disabled. */
+extern void sepol_set_delusers(int on);
+
+/*--------end compatibility----------*/
+
+/* Modify the user, or add it, if the key is not found */
+extern int sepol_user_modify(sepol_handle_t * handle,
+			     sepol_policydb_t * policydb,
+			     const sepol_user_key_t * key,
+			     const sepol_user_t * data);
+
+/* Return the number of users */
+extern int sepol_user_count(sepol_handle_t * handle,
+			    const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified user exists */
+extern int sepol_user_exists(sepol_handle_t * handle,
+			     const sepol_policydb_t * policydb,
+			     const sepol_user_key_t * key, int *response);
+
+/* Query a user - returns the user or NULL if not found */
+extern int sepol_user_query(sepol_handle_t * handle,
+			    const sepol_policydb_t * p,
+			    const sepol_user_key_t * key,
+			    sepol_user_t ** response);
+
+/* Iterate the users
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+extern int sepol_user_iterate(sepol_handle_t * handle,
+			      const sepol_policydb_t * policydb,
+			      int (*fn) (const sepol_user_t * user,
+					 void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/man/Makefile b/libsepol/man/Makefile
new file mode 100644
index 0000000..1192433
--- /dev/null
+++ b/libsepol/man/Makefile
@@ -0,0 +1,12 @@
+# Installation directories.
+MAN8DIR ?= $(DESTDIR)/usr/share/man/man8
+MAN3DIR ?= $(DESTDIR)/usr/share/man/man3
+
+all:
+
+install: all
+	mkdir -p $(MAN3DIR)
+	mkdir -p $(MAN8DIR)
+	install -m 644 man3/*.3 $(MAN3DIR)
+	install -m 644 man8/*.8 $(MAN8DIR)
+
diff --git a/libsepol/man/man3/sepol_check_context.3 b/libsepol/man/man3/sepol_check_context.3
new file mode 100644
index 0000000..4a3c57d
--- /dev/null
+++ b/libsepol/man/man3/sepol_check_context.3
@@ -0,0 +1,25 @@
+.TH "sepol_check_context" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_check_context \- Check the validity of a security context against a binary policy.
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_check_context(const char *" context ");"
+.sp
+.BI "int sepol_set_policydb_from_file(FILE *" fp ");"
+
+.SH "DESCRIPTION"
+.B sepol_check_context
+checks the validity of a security context against a binary policy
+previously loaded from a file via
+.B sepol_set_policydb_from_file.
+It is used by 
+.B setfiles -c
+to validate a file contexts configuration against the binary policy
+upon policy builds.  For validating a context against the active
+policy on a SELinux system, use
+.B security_check_context
+from libselinux instead.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 with errno set otherwise.
diff --git a/libsepol/man/man3/sepol_genbools.3 b/libsepol/man/man3/sepol_genbools.3
new file mode 100644
index 0000000..ca5b5a6
--- /dev/null
+++ b/libsepol/man/man3/sepol_genbools.3
@@ -0,0 +1,30 @@
+.TH "sepol_genbools" "3" "11 August 2004" "sds@epoch.ncsc.mil" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genbools(void *" data ", size_t "len ", char *" boolpath );
+.br
+.BI "int sepol_genbools_array(void *" data ", size_t " len ", char **" names ", int *" values ", int " nel );
+
+.SH "DESCRIPTION"
+.B sepol_genbools
+rewrites a binary policy stored in the memory region described by
+(data, len) to use the boolean settings specified in the file named by
+boolpath.  The boolean settings are specified by name=value lines
+where value may be 0 or false to disable or 1 or true to enable.  The
+binary policy is rewritten in place in memory.
+
+.B sepol_genbools_array
+does likewise, but obtains the boolean settings from the parallel arrays
+(names, values) with nel elements each.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that the boolean file did not exist.
+An errno of EINVAL indicates that one or more booleans listed in the
+boolean file was undefined in the policy or had an invalid value specified;
+in this case, the binary policy is still rewritten but any invalid
+boolean settings are ignored.
+
diff --git a/libsepol/man/man3/sepol_genusers.3 b/libsepol/man/man3/sepol_genusers.3
new file mode 100644
index 0000000..1f820ff
--- /dev/null
+++ b/libsepol/man/man3/sepol_genusers.3
@@ -0,0 +1,54 @@
+.TH "sepol_genusers" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genusers \- Generate a new binary policy image with a customized user configuration
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genusers(void *" data ", size_t "len ", const char *" usersdir ", void *" newdata ", size_t *" newlen);
+.sp
+.BI "void sepol_set_delusers(int " on ");"
+
+.SH "DESCRIPTION"
+.B sepol_genusers
+generates a new binary policy image from 
+an existing binary policy image stored in the memory region described by
+the starting address
+.I data
+and the length
+.I len
+and a pair of user configuration files named 
+.B system.users 
+and
+.B local.users
+from the directory specified by
+.I usersdir.
+The resulting binary policy is placed into dynamically allocated
+memory and the variables
+.I newdata
+and
+.I newlen
+are set to refer to the new binary image's starting address and length.
+The original binary policy image is not modified.
+
+By default, 
+.B sepol_genusers
+will preserve user entries that are defined in the original binary policy image
+but not defined in the user configuration files.  If such user entries
+should instead by omitted entirely from the new binary policy image, then
+the
+.B sepol_set_delusers
+function may be called with 
+.I on
+set to 1 prior to calling
+.B sepol_genusers
+in order to enable deletion of such users.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that one or both of the user
+configuration files did not exist.  An errno of EINVAL indicates that
+either the original binary policy image or the generated one were
+invalid.  An errno of ENOMEM indicates that insufficient memory was
+available to process the original binary policy image or to generate
+the new policy image.  Invalid entries in the user configuration files
+are skipped with a warning.
diff --git a/libsepol/man/man8/chkcon.8 b/libsepol/man/man8/chkcon.8
new file mode 100644
index 0000000..f8d75df
--- /dev/null
+++ b/libsepol/man/man8/chkcon.8
@@ -0,0 +1,41 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; 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.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual 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 manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH CHKCON 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+chkcon \-  determine if a security context is valid for a given binary policy
+.SH SYNOPSIS
+chkcon policy_file context
+.SH DESCRIPTION
+This utility validates (the string representation of) a security context
+specified by the argument
+.I context
+against configuration data read in from a policy database binary
+representation file specified by the argument
+.I policy_file.
+.SH FILES
+policy file
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
+
diff --git a/libsepol/man/man8/genpolbools.8 b/libsepol/man/man8/genpolbools.8
new file mode 100644
index 0000000..afeaced
--- /dev/null
+++ b/libsepol/man/man8/genpolbools.8
@@ -0,0 +1,16 @@
+.TH "genpolbools" "8" "11 August 2004" "sds@epoch.ncsc.mil" "SELinux Command Line documentation"
+.SH "NAME"
+genpolbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B genpolbools oldpolicy booleans newpolicy
+
+.SH "DESCRIPTION"
+.B genpolbools
+rewrites an existing binary policy with different boolean settings,
+generating a new binary policy.  The booleans file specifies the 
+different boolean settings using name=value lines, where value
+can be 0 or false to disable the boolean or 1 or true to enable it.
+
+
+
+
diff --git a/libsepol/man/man8/genpolusers.8 b/libsepol/man/man8/genpolusers.8
new file mode 100644
index 0000000..34d729a
--- /dev/null
+++ b/libsepol/man/man8/genpolusers.8
@@ -0,0 +1,42 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; 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.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual 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 manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH GENPOLUSERS 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+genpolusers \- Generate new binary policy with updated user configuration
+.SH SYNOPSIS
+genpolusers in-policy usersdir out-policy
+.SH DESCRIPTION
+Given an existing binary policy file 
+.I in\-policy, 
+generate a new binary policy 
+.I out\-policy 
+with an updated user configuration based on any 
+.B system.users 
+and
+.B local.users 
+files in the specified 
+.I usersdir.
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
diff --git a/libsepol/src/Makefile b/libsepol/src/Makefile
new file mode 100644
index 0000000..c0c3274
--- /dev/null
+++ b/libsepol/src/Makefile
@@ -0,0 +1,83 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCLUDEDIR ?= $(PREFIX)/include
+LIBDIR ?= $(PREFIX)/lib
+SHLIBDIR ?= $(DESTDIR)/lib
+RANLIB ?= ranlib
+LIBBASE ?= $(shell basename $(LIBDIR))
+CILDIR ?= ../cil
+
+VERSION = $(shell cat ../VERSION)
+LIBVERSION = 1
+
+LEX = flex
+CIL_GENERATED = $(CILDIR)/src/cil_lexer.c
+
+LIBA=libsepol.a 
+TARGET=libsepol.so
+LIBPC=libsepol.pc
+LIBMAP=libsepol.map
+LIBSO=$(TARGET).$(LIBVERSION)
+OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
+LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
+CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-format-attribute -O2
+
+override CFLAGS += -I. -I../include -D_GNU_SOURCE
+
+ifneq ($(DISABLE_CIL),y)
+OBJS += $(sort $(patsubst %.c,%.o,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED)))
+LOBJS += $(sort $(patsubst %.c,%.lo,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED)))
+override CFLAGS += -I$(CILDIR)/include
+endif
+
+
+all: $(LIBA) $(LIBSO) $(LIBPC)
+
+
+$(LIBA):  $(OBJS)
+	$(AR) rcs $@ $^
+	$(RANLIB) $@
+
+$(LIBSO): $(LOBJS) $(LIBMAP)
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $(LOBJS) -Wl,-soname,$(LIBSO),--version-script=$(LIBMAP),-z,defs
+	ln -sf $@ $(TARGET) 
+
+$(LIBPC): $(LIBPC).in ../VERSION
+	sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@
+
+$(LIBMAP): $(LIBMAP).in
+ifneq ($(DISABLE_CIL),y)
+	cp $< $@
+else
+	sed -e '/^\s*cil_/d' < $< > $@
+endif
+
+ifneq ($(DISABLE_CIL),y)
+$(CILDIR)/src/cil_lexer.c: $(CILDIR)/src/cil_lexer.l
+	$(LEX) -t $< > $@
+endif
+
+%.o:  %.c 
+	$(CC) $(CFLAGS) -fPIC -c -o $@ $<
+
+%.lo:  %.c
+	$(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $<
+
+install: all
+	test -d $(LIBDIR) || install -m 755 -d $(LIBDIR)
+	install -m 644 $(LIBA) $(LIBDIR)
+	test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR)
+	install -m 755 $(LIBSO) $(SHLIBDIR)
+	test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig
+	install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig
+	ln -sf --relative $(SHLIBDIR)/$(LIBSO) $(LIBDIR)/$(TARGET)
+
+relabel:
+	/sbin/restorecon $(SHLIBDIR)/$(LIBSO)
+
+clean: 
+	-rm -f $(LIBPC) $(LIBMAP) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) $(CIL_GENERATED)
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
new file mode 100644
index 0000000..a4be880
--- /dev/null
+++ b/libsepol/src/assertion.c
@@ -0,0 +1,556 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Assertion checker for avtab entries, taken from
+ * checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov>
+ *
+ * Copyright (C) 2005 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 <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "private.h"
+#include "debug.h"
+
+struct avtab_match_args {
+	sepol_handle_t *handle;
+	policydb_t *p;
+	avrule_t *avrule;
+	avtab_t *avtab;
+	unsigned long errors;
+};
+
+static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
+			   unsigned int stype, unsigned int ttype,
+			   const class_perm_node_t *curperm, uint32_t perms)
+{
+	if (avrule->source_filename) {
+		ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };",
+		    avrule->source_line, avrule->source_filename, avrule->line,
+		    p->p_type_val_to_name[stype],
+		    p->p_type_val_to_name[ttype],
+		    p->p_class_val_to_name[curperm->tclass - 1],
+		    sepol_av_to_string(p, curperm->tclass, perms));
+	} else if (avrule->line) {
+		ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
+		    avrule->line, p->p_type_val_to_name[stype],
+		    p->p_type_val_to_name[ttype],
+		    p->p_class_val_to_name[curperm->tclass - 1],
+		    sepol_av_to_string(p, curperm->tclass, perms));
+	} else {
+		ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
+		    p->p_type_val_to_name[stype],
+		    p->p_type_val_to_name[ttype],
+		    p->p_class_val_to_name[curperm->tclass - 1],
+		    sepol_av_to_string(p, curperm->tclass, perms));
+	}
+}
+
+static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
+{
+	for (; cp; cp = cp->next) {
+		if ((cp->tclass == class) && (cp->data & data)) {
+			break;
+		}
+	}
+	if (!cp)
+		return 0;
+
+	return 1;
+}
+
+static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
+	size_t i;
+	for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
+		if (perms1[i] & perms2[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int check_extended_permissions(av_extended_perms_t *neverallow, avtab_extended_perms_t *allow)
+{
+	int rc = 0;
+	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		if (neverallow->driver == allow->driver)
+			rc = extended_permissions_and(neverallow->perms, allow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		rc = xperm_test(neverallow->driver, allow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		rc = xperm_test(allow->driver, neverallow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		rc = extended_permissions_and(neverallow->perms, allow->perms);
+	}
+
+	return rc;
+}
+
+/* Compute which allowed extended permissions violate the neverallow rule */
+static void extended_permissions_violated(avtab_extended_perms_t *result,
+					av_extended_perms_t *neverallow,
+					avtab_extended_perms_t *allow)
+{
+	size_t i;
+	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = allow->driver;
+		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+			result->perms[i] = neverallow->perms[i] & allow->perms[i];
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = neverallow->driver;
+		memcpy(result->perms, neverallow->perms, sizeof(result->perms));
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = allow->driver;
+		memcpy(result->perms, allow->perms, sizeof(result->perms));
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		result->specified = AVTAB_XPERMS_IOCTLDRIVER;
+		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+			result->perms[i] = neverallow->perms[i] & allow->perms[i];
+	}
+}
+
+/* Same scenarios of interest as check_assertion_extended_permissions */
+static int report_assertion_extended_permissions(sepol_handle_t *handle,
+				policydb_t *p, const avrule_t *avrule,
+				unsigned int stype, unsigned int ttype,
+				const class_perm_node_t *curperm, uint32_t perms,
+				avtab_key_t *k, avtab_t *avtab)
+{
+	avtab_ptr_t node;
+	avtab_key_t tmp_key;
+	avtab_extended_perms_t *xperms;
+	avtab_extended_perms_t error;
+	ebitmap_t *sattr = &p->type_attr_map[stype];
+	ebitmap_t *tattr = &p->type_attr_map[ttype];
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+	int rc = 1;
+	int ret = 0;
+
+	memcpy(&tmp_key, k, sizeof(avtab_key_t));
+	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+	ebitmap_for_each_bit(sattr, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			tmp_key.source_type = i + 1;
+			tmp_key.target_type = j + 1;
+			for (node = avtab_search_node(avtab, &tmp_key);
+			     node;
+			     node = avtab_search_node_next(node, tmp_key.specified)) {
+				xperms = node->datum.xperms;
+				if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+						&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+					continue;
+
+				rc = check_extended_permissions(avrule->xperms, xperms);
+				/* failure on the extended permission check_extended_permissions */
+				if (rc) {
+					extended_permissions_violated(&error, avrule->xperms, xperms);
+					ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+							"allowxperm %s %s:%s %s;",
+							avrule->source_line, avrule->source_filename, avrule->line,
+							p->p_type_val_to_name[i],
+							p->p_type_val_to_name[j],
+							p->p_class_val_to_name[curperm->tclass - 1],
+							sepol_extended_perms_to_string(&error));
+
+					rc = 0;
+					ret++;
+				}
+			}
+		}
+	}
+
+	/* failure on the regular permissions */
+	if (rc) {
+		ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+				"allow %s %s:%s {%s };",
+				avrule->source_line, avrule->source_filename, avrule->line,
+				p->p_type_val_to_name[stype],
+				p->p_type_val_to_name[ttype],
+				p->p_class_val_to_name[curperm->tclass - 1],
+				sepol_av_to_string(p, curperm->tclass, perms));
+		ret++;
+
+	}
+
+	return ret;
+}
+
+static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
+{
+	int rc = 0;
+	struct avtab_match_args *a = (struct avtab_match_args *)args;
+	sepol_handle_t *handle = a->handle;
+	policydb_t *p = a->p;
+	avtab_t *avtab = a->avtab;
+	avrule_t *avrule = a->avrule;
+	class_perm_node_t *cp;
+	uint32_t perms;
+	ebitmap_t src_matches, tgt_matches, matches;
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+
+	if (k->specified != AVTAB_ALLOWED)
+		return 0;
+
+	if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
+		return 0;
+
+	ebitmap_init(&src_matches);
+	ebitmap_init(&tgt_matches);
+	ebitmap_init(&matches);
+
+	rc = ebitmap_and(&src_matches, &avrule->stypes.types,
+			 &p->attr_type_map[k->source_type - 1]);
+	if (rc)
+		goto oom;
+
+	if (ebitmap_length(&src_matches) == 0)
+		goto exit;
+
+	if (avrule->flags == RULE_SELF) {
+		rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]);
+		if (rc)
+			goto oom;
+		rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
+		if (rc)
+			goto oom;
+	} else {
+		rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
+		if (rc)
+			goto oom;
+	}
+
+	if (ebitmap_length(&tgt_matches) == 0)
+		goto exit;
+
+	for (cp = avrule->perms; cp; cp = cp->next) {
+
+		perms = cp->data & d->data;
+		if ((cp->tclass != k->target_class) || !perms) {
+			continue;
+		}
+
+		ebitmap_for_each_bit(&src_matches, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			ebitmap_for_each_bit(&tgt_matches, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+
+				if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+					a->errors += report_assertion_extended_permissions(handle,p, avrule,
+											i, j, cp, perms, k, avtab);
+				} else {
+					a->errors++;
+					report_failure(handle, p, avrule, i, j, cp, perms);
+				}
+			}
+		}
+	}
+	goto exit;
+
+oom:
+	ERR(NULL, "Out of memory - unable to check neverallows");
+
+exit:
+	ebitmap_destroy(&src_matches);
+	ebitmap_destroy(&tgt_matches);
+	ebitmap_destroy(&matches);
+	return rc;
+}
+
+int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
+{
+	int rc;
+	struct avtab_match_args args;
+
+	args.handle = handle;
+	args.p = p;
+	args.avrule = avrule;
+	args.errors = 0;
+
+	rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
+	if (rc)
+		goto oom;
+
+	rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
+	if (rc)
+		goto oom;
+
+	return args.errors;
+
+oom:
+	return rc;
+}
+
+/*
+ * Look up the extended permissions in avtab and verify that neverallowed
+ * permissions are not granted.
+ */
+static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t *avtab,
+						unsigned int stype, unsigned int ttype,
+						avtab_key_t *k, policydb_t *p)
+{
+	avtab_ptr_t node;
+	avtab_key_t tmp_key;
+	avtab_extended_perms_t *xperms;
+	av_extended_perms_t *neverallow_xperms = avrule->xperms;
+	ebitmap_t *sattr = &p->type_attr_map[stype];
+	ebitmap_t *tattr = &p->type_attr_map[ttype];
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+	int rc = 1;
+
+	memcpy(&tmp_key, k, sizeof(avtab_key_t));
+	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+	ebitmap_for_each_bit(sattr, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			tmp_key.source_type = i + 1;
+			tmp_key.target_type = j + 1;
+			for (node = avtab_search_node(avtab, &tmp_key);
+			     node;
+			     node = avtab_search_node_next(node, tmp_key.specified)) {
+				xperms = node->datum.xperms;
+
+				if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+						&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+					continue;
+				rc = check_extended_permissions(neverallow_xperms, xperms);
+				if (rc)
+					break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * When the ioctl permission is granted on an avtab entry that matches an
+ * avrule neverallowxperm entry, enumerate over the matching
+ * source/target/class sets to determine if the extended permissions exist
+ * and if the neverallowed ioctls are granted.
+ *
+ * Four scenarios of interest:
+ * 1. PASS - the ioctl permission is not granted for this source/target/class
+ *    This case is handled in check_assertion_avtab_match
+ * 2. PASS - The ioctl permission is granted AND the extended permission
+ *    is NOT granted
+ * 3. FAIL - The ioctl permission is granted AND no extended permissions
+ *    exist
+ * 4. FAIL - The ioctl permission is granted AND the extended permission is
+ *    granted
+ */
+static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
+						avtab_key_t *k, policydb_t *p)
+{
+	ebitmap_t src_matches, tgt_matches, matches;
+	unsigned int i, j;
+	ebitmap_node_t *snode, *tnode;
+	class_perm_node_t *cp;
+	int rc;
+	int ret = 1;
+
+	ebitmap_init(&src_matches);
+	ebitmap_init(&tgt_matches);
+	ebitmap_init(&matches);
+	rc = ebitmap_and(&src_matches, &avrule->stypes.types,
+			 &p->attr_type_map[k->source_type - 1]);
+	if (rc)
+		goto oom;
+
+	if (ebitmap_length(&src_matches) == 0)
+		goto exit;
+
+	if (avrule->flags == RULE_SELF) {
+		rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1],
+				&p->attr_type_map[k->target_type - 1]);
+		if (rc)
+			goto oom;
+		rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
+		if (rc)
+			goto oom;
+	} else {
+		rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types,
+				&p->attr_type_map[k->target_type -1]);
+		if (rc)
+			goto oom;
+	}
+
+	if (ebitmap_length(&tgt_matches) == 0)
+		goto exit;
+
+	for (cp = avrule->perms; cp; cp = cp->next) {
+		if (cp->tclass != k->target_class)
+			continue;
+		ebitmap_for_each_bit(&src_matches, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			ebitmap_for_each_bit(&tgt_matches, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+
+				ret = check_assertion_extended_permissions_avtab(
+						avrule, avtab, i, j, k, p);
+				if (ret)
+					goto exit;
+			}
+		}
+	}
+	goto exit;
+
+oom:
+	ERR(NULL, "Out of memory - unable to check neverallows");
+
+exit:
+	ebitmap_destroy(&src_matches);
+	ebitmap_destroy(&tgt_matches);
+	ebitmap_destroy(&matches);
+	return ret;
+}
+
+static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
+{
+	int rc;
+	struct avtab_match_args *a = (struct avtab_match_args *)args;
+	policydb_t *p = a->p;
+	avrule_t *avrule = a->avrule;
+	avtab_t *avtab = a->avtab;
+
+	if (k->specified != AVTAB_ALLOWED)
+		goto exit;
+
+	if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
+		goto exit;
+
+	rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
+	if (rc == 0)
+		goto exit;
+
+	if (avrule->flags == RULE_SELF) {
+		/* If the neverallow uses SELF, then it is not enough that the
+		 * neverallow's source matches the src and tgt of the rule being checked.
+		 * It must match the same thing in the src and tgt, so AND the source
+		 * and target together and check for a match on the result.
+		 */
+		ebitmap_t match;
+		rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] );
+		if (rc) {
+			ebitmap_destroy(&match);
+			goto oom;
+		}
+		rc = ebitmap_match_any(&avrule->stypes.types, &match);
+		ebitmap_destroy(&match);
+	} else {
+		rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
+	}
+	if (rc == 0)
+		goto exit;
+
+	if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+		rc = check_assertion_extended_permissions(avrule, avtab, k, p);
+		if (rc == 0)
+			goto exit;
+	}
+	return 1;
+
+exit:
+	return 0;
+
+oom:
+	ERR(NULL, "Out of memory - unable to check neverallows");
+	return rc;
+}
+
+int check_assertion(policydb_t *p, avrule_t *avrule)
+{
+	int rc;
+	struct avtab_match_args args;
+
+	args.handle = NULL;
+	args.p = p;
+	args.avrule = avrule;
+	args.errors = 0;
+	args.avtab = &p->te_avtab;
+
+	rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
+
+	if (rc == 0) {
+		args.avtab = &p->te_cond_avtab;
+		rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
+	}
+
+	return rc;
+}
+
+int check_assertions(sepol_handle_t * handle, policydb_t * p,
+		     avrule_t * avrules)
+{
+	int rc;
+	avrule_t *a;
+	unsigned long errors = 0;
+
+	if (!avrules) {
+		/* Since assertions are stored in avrules, if it is NULL
+		   there won't be any to check. This also prevents an invalid
+		   free if the avtabs are never initialized */
+		return 0;
+	}
+
+	for (a = avrules; a != NULL; a = a->next) {
+		if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
+			continue;
+		rc = check_assertion(p, a);
+		if (rc) {
+			rc = report_assertion_failures(handle, p, a);
+			if (rc < 0) {
+				ERR(handle, "Error occurred while checking neverallows");
+				return -1;
+			}
+			errors += rc;
+		}
+	}
+
+	if (errors)
+		ERR(handle, "%lu neverallow failures occurred", errors);
+
+	return errors ? -1 : 0;
+}
diff --git a/libsepol/src/av_permissions.h b/libsepol/src/av_permissions.h
new file mode 100644
index 0000000..97278ed
--- /dev/null
+++ b/libsepol/src/av_permissions.h
@@ -0,0 +1,3 @@
+/* Used by security_compute_av. */
+#define PROCESS__TRANSITION                       0x00000002UL
+#define PROCESS__DYNTRANSITION                    0x00800000UL
diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c
new file mode 100644
index 0000000..84cfaf8
--- /dev/null
+++ b/libsepol/src/avrule_block.c
@@ -0,0 +1,201 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Functions that manipulate a logical block (conditional, optional,
+ * or global scope) for a policy module.
+ *
+ * Copyright (C) 2005 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 <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+/* It is anticipated that there be less declarations within an avrule
+ * block than the global policy.  Thus the symbol table sizes are
+ * smaller than those listed in policydb.c */
+static unsigned int symtab_sizes[SYM_NUM] = {
+	2,
+	4,
+	8,
+	32,
+	16,
+	4,
+	2,
+	2,
+};
+
+avrule_block_t *avrule_block_create(void)
+{
+	avrule_block_t *block;
+	if ((block = calloc(1, sizeof(*block))) == NULL) {
+		return NULL;
+	}
+	return block;
+}
+
+avrule_decl_t *avrule_decl_create(uint32_t decl_id)
+{
+	avrule_decl_t *decl;
+	int i;
+	if ((decl = calloc(1, sizeof(*decl))) == NULL) {
+		return NULL;
+	}
+	decl->decl_id = decl_id;
+	for (i = 0; i < SYM_NUM; i++) {
+		if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
+			avrule_decl_destroy(decl);
+			return NULL;
+		}
+	}
+
+	for (i = 0; i < SYM_NUM; i++) {
+		ebitmap_init(&decl->required.scope[i]);
+		ebitmap_init(&decl->declared.scope[i]);
+	}
+	return decl;
+}
+
+/* note that unlike the other destroy functions, this one does /NOT/
+ * destroy the pointer itself */
+static void scope_index_destroy(scope_index_t * scope)
+{
+	unsigned int i;
+	if (scope == NULL) {
+		return;
+	}
+	for (i = 0; i < SYM_NUM; i++) {
+		ebitmap_destroy(scope->scope + i);
+	}
+	for (i = 0; i < scope->class_perms_len; i++) {
+		ebitmap_destroy(scope->class_perms_map + i);
+	}
+	free(scope->class_perms_map);
+}
+
+void avrule_decl_destroy(avrule_decl_t * x)
+{
+	if (x == NULL) {
+		return;
+	}
+	cond_list_destroy(x->cond_list);
+	avrule_list_destroy(x->avrules);
+	role_trans_rule_list_destroy(x->role_tr_rules);
+	filename_trans_rule_list_destroy(x->filename_trans_rules);
+	role_allow_rule_list_destroy(x->role_allow_rules);
+	range_trans_rule_list_destroy(x->range_tr_rules);
+	scope_index_destroy(&x->required);
+	scope_index_destroy(&x->declared);
+	symtabs_destroy(x->symtab);
+	free(x->module_name);
+	free(x);
+}
+
+void avrule_block_destroy(avrule_block_t * x)
+{
+	avrule_decl_t *decl;
+	if (x == NULL) {
+		return;
+	}
+	decl = x->branch_list;
+	while (decl != NULL) {
+		avrule_decl_t *next_decl = decl->next;
+		avrule_decl_destroy(decl);
+		decl = next_decl;
+	}
+	free(x);
+}
+
+void avrule_block_list_destroy(avrule_block_t * x)
+{
+	while (x != NULL) {
+		avrule_block_t *next = x->next;
+		avrule_block_destroy(x);
+		x = next;
+	}
+}
+
+/* Get a conditional node from a avrule_decl with the same expression.
+ * If that expression does not exist then create one. */
+cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl,
+				cond_list_t * cond)
+{
+	cond_list_t *result;
+	int was_created;
+	result = cond_node_find(p, cond, decl->cond_list, &was_created);
+	if (result != NULL && was_created) {
+		result->next = decl->cond_list;
+		decl->cond_list = result;
+	}
+	return result;
+}
+
+/* Look up an identifier in a policy's scoping table.  If it is there,
+ * marked as SCOPE_DECL, and any of its declaring block has been enabled,
+ * then return 1.  Otherwise return 0. Can only be called after the 
+ * decl_val_to_struct index has been created */
+int is_id_enabled(char *id, policydb_t * p, int symbol_table)
+{
+	scope_datum_t *scope =
+	    (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id);
+	uint32_t i;
+	if (scope == NULL) {
+		return 0;
+	}
+	if (scope->scope != SCOPE_DECL) {
+		return 0;
+	}
+	for (i = 0; i < scope->decl_ids_len; i++) {
+		avrule_decl_t *decl =
+		    p->decl_val_to_struct[scope->decl_ids[i] - 1];
+		if (decl != NULL && decl->enabled) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* Check if a particular permission is present within the given class,
+ * and that the class is enabled.  Returns 1 if both conditions are
+ * true, 0 if neither could be found or if the class id disabled. */
+int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p)
+{
+	class_datum_t *cladatum;
+	perm_datum_t *perm;
+	if (!is_id_enabled(class_id, p, SYM_CLASSES)) {
+		return 0;
+	}
+	cladatum =
+	    (class_datum_t *) hashtab_search(p->p_classes.table, class_id);
+	if (cladatum == NULL) {
+		return 0;
+	}
+	perm = hashtab_search(cladatum->permissions.table, perm_id);
+	if (perm == NULL && cladatum->comdatum != 0) {
+		/* permission was not in this class.  before giving
+		 * up, check the class's parent */
+		perm =
+		    hashtab_search(cladatum->comdatum->permissions.table,
+				   perm_id);
+	}
+	if (perm == NULL) {
+		return 0;
+	}
+	return 1;
+}
diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
new file mode 100644
index 0000000..3854d6f
--- /dev/null
+++ b/libsepol/src/avtab.c
@@ -0,0 +1,626 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * 	Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com>
+ *          and Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc.  James Morris <jmorris@redhat.com>
+ *
+ *      Code cleanup
+ *
+ * Updated: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ * Copyright (C) 2003,2007 Red Hat, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/* 
+ * Implementation of the access vector table type.
+ */
+
+#include <stdlib.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/errcodes.h>
+
+#include "debug.h"
+#include "private.h"
+
+/* Based on MurmurHash3, written by Austin Appleby and placed in the
+ * public domain.
+ */
+static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask)
+{
+	static const uint32_t c1 = 0xcc9e2d51;
+	static const uint32_t c2 = 0x1b873593;
+	static const uint32_t r1 = 15;
+	static const uint32_t r2 = 13;
+	static const uint32_t m  = 5;
+	static const uint32_t n  = 0xe6546b64;
+
+	uint32_t hash = 0;
+
+#define mix(input) { \
+	uint32_t v = input; \
+	v *= c1; \
+	v = (v << r1) | (v >> (32 - r1)); \
+	v *= c2; \
+	hash ^= v; \
+	hash = (hash << r2) | (hash >> (32 - r2)); \
+	hash = hash * m + n; \
+}
+
+	mix(keyp->target_class);
+	mix(keyp->target_type);
+	mix(keyp->source_type);
+
+#undef mix
+
+	hash ^= hash >> 16;
+	hash *= 0x85ebca6b;
+	hash ^= hash >> 13;
+	hash *= 0xc2b2ae35;
+	hash ^= hash >> 16;
+
+	return hash & mask;
+}
+
+static avtab_ptr_t
+avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
+		  avtab_datum_t * datum)
+{
+	avtab_ptr_t newnode;
+	avtab_extended_perms_t *xperms;
+
+	newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
+	if (newnode == NULL)
+		return NULL;
+	memset(newnode, 0, sizeof(struct avtab_node));
+	newnode->key = *key;
+
+	if (key->specified & AVTAB_XPERMS) {
+		xperms = calloc(1, sizeof(avtab_extended_perms_t));
+		if (xperms == NULL) {
+			free(newnode);
+			return NULL;
+		}
+		if (datum->xperms) /* else caller populates xperms */
+			*xperms = *(datum->xperms);
+
+		newnode->datum.xperms = xperms;
+		/* data is usually ignored with xperms, except in the case of
+		 * neverallow checking, which requires permission bits to be set.
+		 * So copy data so it is set in the avtab
+		 */
+		newnode->datum.data = datum->data;
+	} else {
+		newnode->datum = *datum;
+	}
+
+	if (prev) {
+		newnode->next = prev->next;
+		prev->next = newnode;
+	} else {
+		newnode->next = h->htable[hvalue];
+		h->htable[hvalue] = newnode;
+	}
+
+	h->nel++;
+	return newnode;
+}
+
+int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+	int hvalue;
+	avtab_ptr_t prev, cur, newnode;
+	uint16_t specified =
+	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+	if (!h || !h->htable)
+		return SEPOL_ENOMEM;
+
+	hvalue = avtab_hash(key, h->mask);
+	for (prev = NULL, cur = h->htable[hvalue];
+	     cur; prev = cur, cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (specified & cur->key.specified)) {
+			/* Extended permissions are not necessarily unique */
+			if (specified & AVTAB_XPERMS)
+				break;
+			return SEPOL_EEXIST;
+		}
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+
+	newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+	if (!newnode)
+		return SEPOL_ENOMEM;
+
+	return 0;
+}
+
+/* Unlike avtab_insert(), this function allow multiple insertions of the same 
+ * key/specified mask into the table, as needed by the conditional avtab.  
+ * It also returns a pointer to the node inserted.
+ */
+avtab_ptr_t
+avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+	int hvalue;
+	avtab_ptr_t prev, cur, newnode;
+	uint16_t specified =
+	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+	if (!h || !h->htable)
+		return NULL;
+	hvalue = avtab_hash(key, h->mask);
+	for (prev = NULL, cur = h->htable[hvalue];
+	     cur; prev = cur, cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (specified & cur->key.specified))
+			break;
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+	newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+
+	return newnode;
+}
+
+avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key)
+{
+	int hvalue;
+	avtab_ptr_t cur;
+	uint16_t specified =
+	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+	if (!h || !h->htable)
+		return NULL;
+
+	hvalue = avtab_hash(key, h->mask);
+	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (specified & cur->key.specified))
+			return &cur->datum;
+
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+
+	return NULL;
+}
+
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key)
+{
+	int hvalue;
+	avtab_ptr_t cur;
+	uint16_t specified =
+	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+	if (!h || !h->htable)
+		return NULL;
+
+	hvalue = avtab_hash(key, h->mask);
+	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class == cur->key.target_class &&
+		    (specified & cur->key.specified))
+			return cur;
+
+		if (key->source_type < cur->key.source_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type < cur->key.target_type)
+			break;
+		if (key->source_type == cur->key.source_type &&
+		    key->target_type == cur->key.target_type &&
+		    key->target_class < cur->key.target_class)
+			break;
+	}
+	return NULL;
+}
+
+avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified)
+{
+	avtab_ptr_t cur;
+
+	if (!node)
+		return NULL;
+
+	specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+	for (cur = node->next; cur; cur = cur->next) {
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type == cur->key.target_type &&
+		    node->key.target_class == cur->key.target_class &&
+		    (specified & cur->key.specified))
+			return cur;
+
+		if (node->key.source_type < cur->key.source_type)
+			break;
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type < cur->key.target_type)
+			break;
+		if (node->key.source_type == cur->key.source_type &&
+		    node->key.target_type == cur->key.target_type &&
+		    node->key.target_class < cur->key.target_class)
+			break;
+	}
+	return NULL;
+}
+
+void avtab_destroy(avtab_t * h)
+{
+	unsigned int i;
+	avtab_ptr_t cur, temp;
+
+	if (!h || !h->htable)
+		return;
+
+	for (i = 0; i < h->nslot; i++) {
+		cur = h->htable[i];
+		while (cur != NULL) {
+			if (cur->key.specified & AVTAB_XPERMS) {
+				free(cur->datum.xperms);
+			}
+			temp = cur;
+			cur = cur->next;
+			free(temp);
+		}
+		h->htable[i] = NULL;
+	}
+	free(h->htable);
+	h->htable = NULL;
+	h->nslot = 0;
+	h->mask = 0;
+}
+
+int avtab_map(avtab_t * h,
+	      int (*apply) (avtab_key_t * k,
+			    avtab_datum_t * d, void *args), void *args)
+{
+	unsigned int i;
+	int ret;
+	avtab_ptr_t cur;
+
+	if (!h)
+		return 0;
+
+	for (i = 0; i < h->nslot; i++) {
+		cur = h->htable[i];
+		while (cur != NULL) {
+			ret = apply(&cur->key, &cur->datum, args);
+			if (ret)
+				return ret;
+			cur = cur->next;
+		}
+	}
+	return 0;
+}
+
+int avtab_init(avtab_t * h)
+{
+	h->htable = NULL;
+	h->nel = 0;
+	return 0;
+}
+
+int avtab_alloc(avtab_t *h, uint32_t nrules)
+{
+	uint32_t mask = 0;
+	uint32_t shift = 0;
+	uint32_t work = nrules;
+	uint32_t nslot = 0;
+
+	if (nrules == 0)
+		goto out;
+
+	while (work) {
+		work  = work >> 1;
+		shift++;
+	}
+	if (shift > 2)
+		shift = shift - 2;
+	nslot = 1 << shift;
+	if (nslot > MAX_AVTAB_HASH_BUCKETS)
+		nslot = MAX_AVTAB_HASH_BUCKETS;
+	mask = nslot - 1;
+
+	h->htable = calloc(nslot, sizeof(avtab_ptr_t));
+	if (!h->htable)
+		return -1;
+out:
+	h->nel = 0;
+	h->nslot = nslot;
+	h->mask = mask;
+	return 0;
+}
+
+void avtab_hash_eval(avtab_t * h, char *tag)
+{
+	unsigned int i, chain_len, slots_used, max_chain_len;
+	avtab_ptr_t cur;
+
+	slots_used = 0;
+	max_chain_len = 0;
+	for (i = 0; i < h->nslot; i++) {
+		cur = h->htable[i];
+		if (cur) {
+			slots_used++;
+			chain_len = 0;
+			while (cur) {
+				chain_len++;
+				cur = cur->next;
+			}
+
+			if (chain_len > max_chain_len)
+				max_chain_len = chain_len;
+		}
+	}
+
+	printf
+	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
+	     tag, h->nel, slots_used, h->nslot, max_chain_len);
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+	AVTAB_ALLOWED,
+	AVTAB_AUDITDENY,
+	AVTAB_AUDITALLOW,
+	AVTAB_TRANSITION,
+	AVTAB_CHANGE,
+	AVTAB_MEMBER,
+	AVTAB_XPERMS_ALLOWED,
+	AVTAB_XPERMS_AUDITALLOW,
+	AVTAB_XPERMS_DONTAUDIT
+};
+
+int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+		    int (*insertf) (avtab_t * a, avtab_key_t * k,
+				    avtab_datum_t * d, void *p), void *p)
+{
+	uint8_t buf8;
+	uint16_t buf16[4], enabled;
+	uint32_t buf32[8], items, items2, val;
+	avtab_key_t key;
+	avtab_datum_t datum;
+	avtab_extended_perms_t xperms;
+	unsigned set;
+	unsigned int i;
+	int rc;
+
+	memset(&key, 0, sizeof(avtab_key_t));
+	memset(&datum, 0, sizeof(avtab_datum_t));
+	memset(&xperms, 0, sizeof(avtab_extended_perms_t));
+
+	if (vers < POLICYDB_VERSION_AVTAB) {
+		rc = next_entry(buf32, fp, sizeof(uint32_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		items2 = le32_to_cpu(buf32[0]);
+
+		if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) {
+			ERR(fp->handle, "invalid item count");
+			return -1;
+		}
+
+		rc = next_entry(buf32, fp, sizeof(uint32_t) * items2);
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+
+		items = 0;
+		val = le32_to_cpu(buf32[items++]);
+		key.source_type = (uint16_t) val;
+		if (key.source_type != val) {
+			ERR(fp->handle, "truncated source type");
+			return -1;
+		}
+		val = le32_to_cpu(buf32[items++]);
+		key.target_type = (uint16_t) val;
+		if (key.target_type != val) {
+			ERR(fp->handle, "truncated target type");
+			return -1;
+		}
+		val = le32_to_cpu(buf32[items++]);
+		key.target_class = (uint16_t) val;
+		if (key.target_class != val) {
+			ERR(fp->handle, "truncated target class");
+			return -1;
+		}
+
+		val = le32_to_cpu(buf32[items++]);
+		enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+			ERR(fp->handle, "null entry");
+			return -1;
+		}
+		if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+			ERR(fp->handle, "entry has both access "
+			    "vectors and types");
+			return -1;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+			if (val & spec_order[i]) {
+				key.specified = spec_order[i] | enabled;
+				datum.data = le32_to_cpu(buf32[items++]);
+				rc = insertf(a, &key, &datum, p);
+				if (rc)
+					return rc;
+			}
+		}
+
+		if (items != items2) {
+			ERR(fp->handle, "entry only had %d items, "
+			    "expected %d", items2, items);
+			return -1;
+		}
+		return 0;
+	}
+
+	rc = next_entry(buf16, fp, sizeof(uint16_t) * 4);
+	if (rc < 0) {
+		ERR(fp->handle, "truncated entry");
+		return -1;
+	}
+	items = 0;
+	key.source_type = le16_to_cpu(buf16[items++]);
+	key.target_type = le16_to_cpu(buf16[items++]);
+	key.target_class = le16_to_cpu(buf16[items++]);
+	key.specified = le16_to_cpu(buf16[items++]);
+
+	set = 0;
+	for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+		if (key.specified & spec_order[i])
+			set++;
+	}
+	if (!set || set > 1) {
+		ERR(fp->handle, "more than one specifier");
+		return -1;
+	}
+
+	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+			(key.specified & AVTAB_XPERMS)) {
+		ERR(fp->handle, "policy version %u does not support extended "
+				"permissions rules and one was specified\n", vers);
+		return -1;
+	} else if (key.specified & AVTAB_XPERMS) {
+		rc = next_entry(&buf8, fp, sizeof(uint8_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		xperms.specified = buf8;
+		rc = next_entry(&buf8, fp, sizeof(uint8_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		xperms.driver = buf8;
+		rc = next_entry(buf32, fp, sizeof(uint32_t)*8);
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		for (i = 0; i < ARRAY_SIZE(xperms.perms); i++)
+			xperms.perms[i] = le32_to_cpu(buf32[i]);
+		datum.xperms = &xperms;
+	} else {
+		rc = next_entry(buf32, fp, sizeof(uint32_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		datum.data = le32_to_cpu(*buf32);
+	}
+	return insertf(a, &key, &datum, p);
+}
+
+static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d,
+			 void *p __attribute__ ((unused)))
+{
+	return avtab_insert(a, k, d);
+}
+
+int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
+{
+	unsigned int i;
+	int rc;
+	uint32_t buf[1];
+	uint32_t nel;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0) {
+		ERR(fp->handle, "truncated table");
+		goto bad;
+	}
+	nel = le32_to_cpu(buf[0]);
+	if (!nel) {
+		ERR(fp->handle, "table is empty");
+		goto bad;
+	}
+
+	rc = avtab_alloc(a, nel);
+	if (rc) {
+		ERR(fp->handle, "out of memory");
+		goto bad;
+	}
+
+	for (i = 0; i < nel; i++) {
+		rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
+		if (rc) {
+			if (rc == SEPOL_ENOMEM)
+				ERR(fp->handle, "out of memory");
+			if (rc == SEPOL_EEXIST)
+				ERR(fp->handle, "duplicate entry");
+			ERR(fp->handle, "failed on entry %d of %u", i, nel);
+			goto bad;
+		}
+	}
+
+	return 0;
+
+      bad:
+	avtab_destroy(a);
+	return -1;
+}
diff --git a/libsepol/src/boolean_internal.h b/libsepol/src/boolean_internal.h
new file mode 100644
index 0000000..aad7ade
--- /dev/null
+++ b/libsepol/src/boolean_internal.h
@@ -0,0 +1,16 @@
+#ifndef _SEPOL_BOOLEAN_INTERNAL_H_
+#define _SEPOL_BOOLEAN_INTERNAL_H_
+
+#include <sepol/boolean_record.h>
+#include <sepol/booleans.h>
+#include "dso.h"
+
+hidden_proto(sepol_bool_key_create)
+    hidden_proto(sepol_bool_key_unpack)
+    hidden_proto(sepol_bool_get_name)
+    hidden_proto(sepol_bool_set_name)
+    hidden_proto(sepol_bool_get_value)
+    hidden_proto(sepol_bool_set_value)
+    hidden_proto(sepol_bool_create)
+    hidden_proto(sepol_bool_free)
+#endif
diff --git a/libsepol/src/boolean_record.c b/libsepol/src/boolean_record.c
new file mode 100644
index 0000000..8b64413
--- /dev/null
+++ b/libsepol/src/boolean_record.c
@@ -0,0 +1,180 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "boolean_internal.h"
+#include "debug.h"
+
+struct sepol_bool {
+	/* This boolean's name */
+	char *name;
+
+	/* Its value */
+	int value;
+};
+
+struct sepol_bool_key {
+	/* This boolean's name */
+	const char *name;
+};
+
+int sepol_bool_key_create(sepol_handle_t * handle,
+			  const char *name, sepol_bool_key_t ** key_ptr)
+{
+
+	sepol_bool_key_t *tmp_key =
+	    (sepol_bool_key_t *) malloc(sizeof(struct sepol_bool_key));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, " "could not create boolean key");
+		return STATUS_ERR;
+	}
+
+	tmp_key->name = name;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_key_create)
+
+void sepol_bool_key_unpack(const sepol_bool_key_t * key, const char **name)
+{
+
+	*name = key->name;
+}
+
+hidden_def(sepol_bool_key_unpack)
+
+int sepol_bool_key_extract(sepol_handle_t * handle,
+			   const sepol_bool_t * boolean,
+			   sepol_bool_key_t ** key_ptr)
+{
+
+	if (sepol_bool_key_create(handle, boolean->name, key_ptr) < 0) {
+		ERR(handle, "could not extract key from boolean %s",
+		    boolean->name);
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_bool_key_free(sepol_bool_key_t * key)
+{
+	free(key);
+}
+
+int sepol_bool_compare(const sepol_bool_t * boolean,
+		       const sepol_bool_key_t * key)
+{
+
+	return strcmp(boolean->name, key->name);
+}
+
+int sepol_bool_compare2(const sepol_bool_t * boolean,
+			const sepol_bool_t * boolean2)
+{
+
+	return strcmp(boolean->name, boolean2->name);
+}
+
+/* Name */
+const char *sepol_bool_get_name(const sepol_bool_t * boolean)
+{
+
+	return boolean->name;
+}
+
+hidden_def(sepol_bool_get_name)
+
+int sepol_bool_set_name(sepol_handle_t * handle,
+			sepol_bool_t * boolean, const char *name)
+{
+
+	char *tmp_name = strdup(name);
+	if (!tmp_name) {
+		ERR(handle, "out of memory, could not set boolean name");
+		return STATUS_ERR;
+	}
+	free(boolean->name);
+	boolean->name = tmp_name;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_set_name)
+
+/* Value */
+int sepol_bool_get_value(const sepol_bool_t * boolean)
+{
+
+	return boolean->value;
+}
+
+hidden_def(sepol_bool_get_value)
+
+void sepol_bool_set_value(sepol_bool_t * boolean, int value)
+{
+
+	boolean->value = value;
+}
+
+hidden_def(sepol_bool_set_value)
+
+/* Create */
+int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr)
+{
+
+	sepol_bool_t *boolean = (sepol_bool_t *) malloc(sizeof(sepol_bool_t));
+
+	if (!boolean) {
+		ERR(handle, "out of memory, "
+		    "could not create boolean record");
+		return STATUS_ERR;
+	}
+
+	boolean->name = NULL;
+	boolean->value = 0;
+
+	*bool_ptr = boolean;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_create)
+
+/* Deep copy clone */
+int sepol_bool_clone(sepol_handle_t * handle,
+		     const sepol_bool_t * boolean, sepol_bool_t ** bool_ptr)
+{
+
+	sepol_bool_t *new_bool = NULL;
+
+	if (sepol_bool_create(handle, &new_bool) < 0)
+		goto err;
+
+	if (sepol_bool_set_name(handle, new_bool, boolean->name) < 0)
+		goto err;
+
+	new_bool->value = boolean->value;
+
+	*bool_ptr = new_bool;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not clone boolean record");
+	sepol_bool_free(new_bool);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_bool_free(sepol_bool_t * boolean)
+{
+
+	if (!boolean)
+		return;
+
+	free(boolean->name);
+	free(boolean);
+}
+
+hidden_def(sepol_bool_free)
diff --git a/libsepol/src/booleans.c b/libsepol/src/booleans.c
new file mode 100644
index 0000000..c914a28
--- /dev/null
+++ b/libsepol/src/booleans.c
@@ -0,0 +1,215 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "handle.h"
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/booleans.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include "boolean_internal.h"
+
+static int bool_update(sepol_handle_t * handle,
+		       policydb_t * policydb,
+		       const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+	const char *cname;
+	char *name;
+	int value;
+
+	sepol_bool_key_unpack(key, &cname);
+	name = strdup(cname);
+	value = sepol_bool_get_value(data);
+
+	if (!name)
+		goto omem;
+
+	cond_bool_datum_t *datum =
+	    hashtab_search(policydb->p_bools.table, name);
+	if (!datum) {
+		ERR(handle, "boolean %s no longer in policy", name);
+		goto err;
+	}
+	if (value != 0 && value != 1) {
+		ERR(handle, "illegal value %d for boolean %s", value, name);
+		goto err;
+	}
+
+	free(name);
+	datum->state = value;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	free(name);
+	ERR(handle, "could not update boolean %s", cname);
+	return STATUS_ERR;
+}
+
+static int bool_to_record(sepol_handle_t * handle,
+			  const policydb_t * policydb,
+			  int bool_idx, sepol_bool_t ** record)
+{
+
+	const char *name = policydb->p_bool_val_to_name[bool_idx];
+	cond_bool_datum_t *booldatum = policydb->bool_val_to_struct[bool_idx];
+	int value = booldatum->state;
+
+	sepol_bool_t *tmp_record = NULL;
+
+	if (sepol_bool_create(handle, &tmp_record) < 0)
+		goto err;
+
+	if (sepol_bool_set_name(handle, tmp_record, name) < 0)
+		goto err;
+
+	sepol_bool_set_value(tmp_record, value);
+
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not convert boolean %s to record", name);
+	sepol_bool_free(tmp_record);
+	return STATUS_ERR;
+}
+
+int sepol_bool_set(sepol_handle_t * handle,
+		   sepol_policydb_t * p,
+		   const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+	const char *name;
+	sepol_bool_key_unpack(key, &name);
+
+	policydb_t *policydb = &p->p;
+	if (bool_update(handle, policydb, key, data) < 0)
+		goto err;
+
+	if (evaluate_conds(policydb) < 0) {
+		ERR(handle, "error while re-evaluating conditionals");
+		goto err;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not set boolean %s", name);
+	return STATUS_ERR;
+}
+
+int sepol_bool_count(sepol_handle_t * handle __attribute__ ((unused)),
+		     const sepol_policydb_t * p, unsigned int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+	*response = policydb->p_bools.nprim;
+
+	return STATUS_SUCCESS;
+}
+
+int sepol_bool_exists(sepol_handle_t * handle,
+		      const sepol_policydb_t * p,
+		      const sepol_bool_key_t * key, int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+
+	const char *cname;
+	char *name = NULL;
+	sepol_bool_key_unpack(key, &cname);
+	name = strdup(cname);
+
+	if (!name) {
+		ERR(handle, "out of memory, could not check "
+		    "if user %s exists", cname);
+		return STATUS_ERR;
+	}
+
+	*response = (hashtab_search(policydb->p_bools.table, name) != NULL);
+	free(name);
+	return STATUS_SUCCESS;
+}
+
+int sepol_bool_query(sepol_handle_t * handle,
+		     const sepol_policydb_t * p,
+		     const sepol_bool_key_t * key, sepol_bool_t ** response)
+{
+
+	const policydb_t *policydb = &p->p;
+	cond_bool_datum_t *booldatum = NULL;
+
+	const char *cname;
+	char *name = NULL;
+	sepol_bool_key_unpack(key, &cname);
+	name = strdup(cname);
+
+	if (!name)
+		goto omem;
+
+	booldatum = hashtab_search(policydb->p_bools.table, name);
+	if (!booldatum) {
+		*response = NULL;
+		return STATUS_SUCCESS;
+	}
+
+	if (bool_to_record(handle, policydb,
+			   booldatum->s.value - 1, response) < 0)
+		goto err;
+
+	free(name);
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not query boolean %s", cname);
+	free(name);
+	return STATUS_ERR;
+}
+
+int sepol_bool_iterate(sepol_handle_t * handle,
+		       const sepol_policydb_t * p,
+		       int (*fn) (const sepol_bool_t * boolean,
+				  void *fn_arg), void *arg)
+{
+
+	const policydb_t *policydb = &p->p;
+	unsigned int nbools = policydb->p_bools.nprim;
+	sepol_bool_t *boolean = NULL;
+	unsigned int i;
+
+	/* For each boolean */
+	for (i = 0; i < nbools; i++) {
+
+		int status;
+
+		if (bool_to_record(handle, policydb, i, &boolean) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(boolean, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_bool_free(boolean);
+		boolean = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not iterate over booleans");
+	sepol_bool_free(boolean);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c
new file mode 100644
index 0000000..ea47cdd
--- /dev/null
+++ b/libsepol/src/conditional.c
@@ -0,0 +1,923 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *          David Caplan <dac@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 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 <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/conditional.h>
+
+#include "private.h"
+
+/* move all type rules to top of t/f lists to help kernel on evaluation */
+static void cond_optimize(cond_av_list_t ** l)
+{
+	cond_av_list_t *top, *p, *cur;
+
+	top = p = cur = *l;
+
+	while (cur) {
+		if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
+			p->next = cur->next;
+			cur->next = top;
+			top = cur;
+			cur = p->next;
+		} else {
+			p = cur;
+			cur = cur->next;
+		}
+	}
+	*l = top;
+}
+
+/* reorder t/f lists for kernel */
+void cond_optimize_lists(cond_list_t * cl)
+{
+	cond_list_t *n;
+
+	for (n = cl; n != NULL; n = n->next) {
+		cond_optimize(&n->true_list);
+		cond_optimize(&n->false_list);
+	}
+}
+
+static int bool_present(unsigned int target, unsigned int bools[],
+			unsigned int num_bools)
+{
+	unsigned int i = 0;
+	int ret = 1;
+
+	if (num_bools > COND_MAX_BOOLS) {
+		return 0;
+	}
+	while (i < num_bools && target != bools[i])
+		i++;
+	if (i == num_bools)
+		ret = 0;	/* got to end w/o match */
+	return ret;
+}
+
+static int same_bools(cond_node_t * a, cond_node_t * b)
+{
+	unsigned int i, x;
+
+	x = a->nbools;
+
+	/* same number of bools? */
+	if (x != b->nbools)
+		return 0;
+
+	/* make sure all the bools in a are also in b */
+	for (i = 0; i < x; i++)
+		if (!bool_present(a->bool_ids[i], b->bool_ids, x))
+			return 0;
+	return 1;
+}
+
+/*
+ * Determine if two conditional expressions are equal. 
+ */
+int cond_expr_equal(cond_node_t * a, cond_node_t * b)
+{
+	cond_expr_t *cur_a, *cur_b;
+
+	if (a == NULL || b == NULL)
+		return 0;
+
+	if (a->nbools != b->nbools)
+		return 0;
+
+	/* if exprs have <= COND_MAX_BOOLS we can check the precompute values
+	 * for the expressions.
+	 */
+	if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
+		if (!same_bools(a, b))
+			return 0;
+		return (a->expr_pre_comp == b->expr_pre_comp);
+	}
+
+	/* for long expressions we check for exactly the same expression */
+	cur_a = a->expr;
+	cur_b = b->expr;
+	while (1) {
+		if (cur_a == NULL && cur_b == NULL)
+			return 1;
+		else if (cur_a == NULL || cur_b == NULL)
+			return 0;
+		if (cur_a->expr_type != cur_b->expr_type)
+			return 0;
+		if (cur_a->expr_type == COND_BOOL) {
+			if (cur_a->bool != cur_b->bool)
+				return 0;
+		}
+		cur_a = cur_a->next;
+		cur_b = cur_b->next;
+	}
+	return 1;
+}
+
+/* Create a new conditional node, optionally copying
+ * the conditional expression from an existing node.
+ * If node is NULL then a new node will be created
+ * with no conditional expression.
+ */
+cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
+{
+	cond_node_t *new_node;
+	unsigned int i;
+
+	new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
+	if (!new_node) {
+		return NULL;
+	}
+	memset(new_node, 0, sizeof(cond_node_t));
+
+	if (node) {
+		new_node->expr = cond_copy_expr(node->expr);
+		if (!new_node->expr) {
+			free(new_node);
+			return NULL;
+		}
+		new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
+		new_node->nbools = node->nbools;
+		for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
+			new_node->bool_ids[i] = node->bool_ids[i];
+		new_node->expr_pre_comp = node->expr_pre_comp;
+		new_node->flags = node->flags;
+	}
+
+	return new_node;
+}
+
+/* Find a conditional (the needle) within a list of existing ones (the
+ * haystack) that has a matching expression.  If found, return a
+ * pointer to the existing node, setting 'was_created' to 0.
+ * Otherwise create a new one and return it, setting 'was_created' to
+ * 1. */
+cond_node_t *cond_node_find(policydb_t * p,
+			    cond_node_t * needle, cond_node_t * haystack,
+			    int *was_created)
+{
+	while (haystack) {
+		if (cond_expr_equal(needle, haystack)) {
+			*was_created = 0;
+			return haystack;
+		}
+		haystack = haystack->next;
+	}
+	*was_created = 1;
+
+	return cond_node_create(p, needle);
+}
+
+/* return either a pre-existing matching node or create a new node */
+cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+			      cond_node_t * cn)
+{
+	int was_created;
+	cond_node_t *result = cond_node_find(p, cn, list, &was_created);
+	if (result != NULL && was_created) {
+		/* add conditional node to policy list */
+		result->next = p->cond_list;
+		p->cond_list = result;
+	}
+	return result;
+}
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
+{
+
+	cond_expr_t *cur;
+	int s[COND_EXPR_MAXDEPTH];
+	int sp = -1;
+
+	s[0] = -1;
+
+	for (cur = expr; cur != NULL; cur = cur->next) {
+		switch (cur->expr_type) {
+		case COND_BOOL:
+			if (sp == (COND_EXPR_MAXDEPTH - 1))
+				return -1;
+			sp++;
+			s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+			break;
+		case COND_NOT:
+			if (sp < 0)
+				return -1;
+			s[sp] = !s[sp];
+			break;
+		case COND_OR:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] |= s[sp + 1];
+			break;
+		case COND_AND:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] &= s[sp + 1];
+			break;
+		case COND_XOR:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] ^= s[sp + 1];
+			break;
+		case COND_EQ:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] = (s[sp] == s[sp + 1]);
+			break;
+		case COND_NEQ:
+			if (sp < 1)
+				return -1;
+			sp--;
+			s[sp] = (s[sp] != s[sp + 1]);
+			break;
+		default:
+			return -1;
+		}
+	}
+	return s[0];
+}
+
+cond_expr_t *cond_copy_expr(cond_expr_t * expr)
+{
+	cond_expr_t *cur, *head, *tail, *new_expr;
+	tail = head = NULL;
+	cur = expr;
+	while (cur) {
+		new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
+		if (!new_expr)
+			goto free_head;
+		memset(new_expr, 0, sizeof(cond_expr_t));
+
+		new_expr->expr_type = cur->expr_type;
+		new_expr->bool = cur->bool;
+
+		if (!head)
+			head = new_expr;
+		if (tail)
+			tail->next = new_expr;
+		tail = new_expr;
+		cur = cur->next;
+	}
+	return head;
+
+      free_head:
+	while (head) {
+		tail = head->next;
+		free(head);
+		head = tail;
+	}
+	return NULL;
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a cond_node_t and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
+{
+	int new_state;
+	cond_av_list_t *cur;
+
+	new_state = cond_evaluate_expr(p, node->expr);
+	if (new_state != node->cur_state) {
+		node->cur_state = new_state;
+		if (new_state == -1)
+			printf
+			    ("expression result was undefined - disabling all rules.\n");
+		/* turn the rules on or off */
+		for (cur = node->true_list; cur != NULL; cur = cur->next) {
+			if (new_state <= 0) {
+				cur->node->key.specified &= ~AVTAB_ENABLED;
+			} else {
+				cur->node->key.specified |= AVTAB_ENABLED;
+			}
+		}
+
+		for (cur = node->false_list; cur != NULL; cur = cur->next) {
+			/* -1 or 1 */
+			if (new_state) {
+				cur->node->key.specified &= ~AVTAB_ENABLED;
+			} else {
+				cur->node->key.specified |= AVTAB_ENABLED;
+			}
+		}
+	}
+	return 0;
+}
+
+/* precompute and simplify an expression if possible.  If left with !expression, change 
+ * to expression and switch t and f. precompute expression for expressions with limited
+ * number of bools.
+ */
+int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
+{
+	cond_expr_t *ne, *e;
+	cond_av_list_t *tmp;
+	unsigned int i, j, orig_value[COND_MAX_BOOLS];
+	int k;
+	uint32_t test = 0x0;
+	avrule_t *tmp2;
+
+	cn->nbools = 0;
+
+	memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
+	cn->expr_pre_comp = 0x0;
+
+	/* take care of !expr case */
+	ne = NULL;
+	e = cn->expr;
+
+	/* becuase it's RPN look at last element */
+	while (e->next != NULL) {
+		ne = e;
+		e = e->next;
+	}
+	if (e->expr_type == COND_NOT) {
+		if (ne) {
+			ne->next = NULL;
+		} else {	/* ne should never be NULL */
+			printf
+			    ("Found expr with no bools and only a ! - this should never happen.\n");
+			return -1;
+		}
+		/* swap the true and false lists */
+		tmp = cn->true_list;
+		cn->true_list = cn->false_list;
+		cn->false_list = tmp;
+		tmp2 = cn->avtrue_list;
+		cn->avtrue_list = cn->avfalse_list;
+		cn->avfalse_list = tmp2;
+
+		/* free the "not" node in the list */
+		free(e);
+	}
+
+	/* find all the bools in the expression */
+	for (e = cn->expr; e != NULL; e = e->next) {
+		switch (e->expr_type) {
+		case COND_BOOL:
+			i = 0;
+			/* see if we've already seen this bool */
+			if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) {
+				/* count em all but only record up to COND_MAX_BOOLS */
+				if (cn->nbools < COND_MAX_BOOLS)
+					cn->bool_ids[cn->nbools++] = e->bool;
+				else
+					cn->nbools++;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* only precompute for exprs with <= COND_AX_BOOLS */
+	if (cn->nbools <= COND_MAX_BOOLS) {
+		/* save the default values for the bools so we can play with them */
+		for (i = 0; i < cn->nbools; i++) {
+			orig_value[i] =
+			    p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
+		}
+
+		/* loop through all possible combinations of values for bools in expression */
+		for (test = 0x0; test < (0x1U << cn->nbools); test++) {
+			/* temporarily set the value for all the bools in the
+			 * expression using the corr.  bit in test */
+			for (j = 0; j < cn->nbools; j++) {
+				p->bool_val_to_struct[cn->bool_ids[j] -
+						      1]->state =
+				    (test & (0x1 << j)) ? 1 : 0;
+			}
+			k = cond_evaluate_expr(p, cn->expr);
+			if (k == -1) {
+				printf
+				    ("While testing expression, expression result "
+				     "was undefined - this should never happen.\n");
+				return -1;
+			}
+			/* set the bit if expression evaluates true */
+			if (k)
+				cn->expr_pre_comp |= 0x1 << test;
+		}
+
+		/* restore bool default values */
+		for (i = 0; i < cn->nbools; i++)
+			p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
+			    orig_value[i];
+	}
+	return 0;
+}
+
+int evaluate_conds(policydb_t * p)
+{
+	int ret;
+	cond_node_t *cur;
+
+	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+		ret = evaluate_cond_node(p, cur);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+int cond_policydb_init(policydb_t * p)
+{
+	p->bool_val_to_struct = NULL;
+	p->cond_list = NULL;
+	if (avtab_init(&p->te_cond_avtab))
+		return -1;
+
+	return 0;
+}
+
+void cond_av_list_destroy(cond_av_list_t * list)
+{
+	cond_av_list_t *cur, *next;
+	for (cur = list; cur != NULL; cur = next) {
+		next = cur->next;
+		/* the avtab_ptr_t node is destroy by the avtab */
+		free(cur);
+	}
+}
+
+void cond_expr_destroy(cond_expr_t * expr)
+{
+	cond_expr_t *cur_expr, *next_expr;
+
+	if (!expr)
+		return;
+
+	for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
+		next_expr = cur_expr->next;
+		free(cur_expr);
+	}
+}
+
+void cond_node_destroy(cond_node_t * node)
+{
+	if (!node)
+		return;
+
+	cond_expr_destroy(node->expr);
+	avrule_list_destroy(node->avtrue_list);
+	avrule_list_destroy(node->avfalse_list);
+	cond_av_list_destroy(node->true_list);
+	cond_av_list_destroy(node->false_list);
+}
+
+void cond_list_destroy(cond_list_t * list)
+{
+	cond_node_t *next, *cur;
+
+	if (list == NULL)
+		return;
+
+	for (cur = list; cur != NULL; cur = next) {
+		next = cur->next;
+		cond_node_destroy(cur);
+		free(cur);
+	}
+}
+
+void cond_policydb_destroy(policydb_t * p)
+{
+	if (p->bool_val_to_struct != NULL)
+		free(p->bool_val_to_struct);
+	avtab_destroy(&p->te_cond_avtab);
+	cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(policydb_t * p)
+{
+	if (p->bool_val_to_struct)
+		free(p->bool_val_to_struct);
+	p->bool_val_to_struct = (cond_bool_datum_t **)
+	    malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *));
+	if (!p->bool_val_to_struct)
+		return -1;
+	return 0;
+}
+
+int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
+		      __attribute__ ((unused)))
+{
+	if (key)
+		free(key);
+	free(datum);
+	return 0;
+}
+
+int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	cond_bool_datum_t *booldatum;
+
+	booldatum = datum;
+	p = datap;
+
+	if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
+		return -EINVAL;
+
+	p->p_bool_val_to_name[booldatum->s.value - 1] = key;
+	p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
+
+	return 0;
+}
+
+static int bool_isvalid(cond_bool_datum_t * b)
+{
+	if (!(b->state == 0 || b->state == 1))
+		return 0;
+	return 1;
+}
+
+int cond_read_bool(policydb_t * p,
+		   hashtab_t h,
+		   struct policy_file *fp)
+{
+	char *key = 0;
+	cond_bool_datum_t *booldatum;
+	uint32_t buf[3], len;
+	int rc;
+
+	booldatum = malloc(sizeof(cond_bool_datum_t));
+	if (!booldatum)
+		return -1;
+	memset(booldatum, 0, sizeof(cond_bool_datum_t));
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+	if (rc < 0)
+		goto err;
+
+	booldatum->s.value = le32_to_cpu(buf[0]);
+	booldatum->state = le32_to_cpu(buf[1]);
+
+	if (!bool_isvalid(booldatum))
+		goto err;
+
+	len = le32_to_cpu(buf[2]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto err;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto err;
+	key[len] = 0;
+
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto err;
+		booldatum->flags = le32_to_cpu(buf[0]);
+	}
+
+	if (hashtab_insert(h, key, booldatum))
+		goto err;
+
+	return 0;
+      err:
+	cond_destroy_bool(key, booldatum, 0);
+	return -1;
+}
+
+struct cond_insertf_data {
+	struct policydb *p;
+	cond_av_list_t *other;
+	cond_av_list_t *head;
+	cond_av_list_t *tail;
+};
+
+static int cond_insertf(avtab_t * a
+			__attribute__ ((unused)), avtab_key_t * k,
+			avtab_datum_t * d, void *ptr)
+{
+	struct cond_insertf_data *data = ptr;
+	struct policydb *p = data->p;
+	cond_av_list_t *other = data->other, *list, *cur;
+	avtab_ptr_t node_ptr;
+	uint8_t found;
+
+	/*
+	 * For type rules we have to make certain there aren't any
+	 * conflicting rules by searching the te_avtab and the
+	 * cond_te_avtab.
+	 */
+	if (k->specified & AVTAB_TYPE) {
+		if (avtab_search(&p->te_avtab, k)) {
+			printf
+			    ("security: type rule already exists outside of a conditional.");
+			goto err;
+		}
+		/*
+		 * If we are reading the false list other will be a pointer to
+		 * the true list. We can have duplicate entries if there is only
+		 * 1 other entry and it is in our true list.
+		 *
+		 * If we are reading the true list (other == NULL) there shouldn't
+		 * be any other entries.
+		 */
+		if (other) {
+			node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+			if (node_ptr) {
+				if (avtab_search_node_next
+				    (node_ptr, k->specified)) {
+					printf
+					    ("security: too many conflicting type rules.");
+					goto err;
+				}
+				found = 0;
+				for (cur = other; cur != NULL; cur = cur->next) {
+					if (cur->node == node_ptr) {
+						found = 1;
+						break;
+					}
+				}
+				if (!found) {
+					printf
+					    ("security: conflicting type rules.\n");
+					goto err;
+				}
+			}
+		} else {
+			if (avtab_search(&p->te_cond_avtab, k)) {
+				printf
+				    ("security: conflicting type rules when adding type rule for true.\n");
+				goto err;
+			}
+		}
+	}
+
+	node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+	if (!node_ptr) {
+		printf("security: could not insert rule.");
+		goto err;
+	}
+	node_ptr->parse_context = (void *)1;
+
+	list = malloc(sizeof(cond_av_list_t));
+	if (!list)
+		goto err;
+	memset(list, 0, sizeof(cond_av_list_t));
+
+	list->node = node_ptr;
+	if (!data->head)
+		data->head = list;
+	else
+		data->tail->next = list;
+	data->tail = list;
+	return 0;
+
+      err:
+	cond_av_list_destroy(data->head);
+	data->head = NULL;
+	return -1;
+}
+
+static int cond_read_av_list(policydb_t * p, void *fp,
+			     cond_av_list_t ** ret_list, cond_av_list_t * other)
+{
+	unsigned int i;
+	int rc;
+	uint32_t buf[1], len;
+	struct cond_insertf_data data;
+
+	*ret_list = NULL;
+
+	len = 0;
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+
+	len = le32_to_cpu(buf[0]);
+	if (len == 0) {
+		return 0;
+	}
+
+	data.p = p;
+	data.other = other;
+	data.head = NULL;
+	data.tail = NULL;
+	for (i = 0; i < len; i++) {
+		rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
+				     cond_insertf, &data);
+		if (rc)
+			return rc;
+
+	}
+
+	*ret_list = data.head;
+	return 0;
+}
+
+static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
+{
+	if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
+		printf
+		    ("security: conditional expressions uses unknown operator.\n");
+		return 0;
+	}
+
+	if (expr->bool > p->p_bools.nprim) {
+		printf
+		    ("security: conditional expressions uses unknown bool.\n");
+		return 0;
+	}
+	return 1;
+}
+
+static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
+{
+	uint32_t buf[2];
+	int len, i, rc;
+	cond_expr_t *expr = NULL, *last = NULL;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto err;
+
+	node->cur_state = le32_to_cpu(buf[0]);
+
+	len = 0;
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto err;
+
+	/* expr */
+	len = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < len; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0)
+			goto err;
+
+		expr = malloc(sizeof(cond_expr_t));
+		if (!expr) {
+			goto err;
+		}
+		memset(expr, 0, sizeof(cond_expr_t));
+
+		expr->expr_type = le32_to_cpu(buf[0]);
+		expr->bool = le32_to_cpu(buf[1]);
+
+		if (!expr_isvalid(p, expr)) {
+			free(expr);
+			goto err;
+		}
+
+		if (i == 0) {
+			node->expr = expr;
+		} else {
+			last->next = expr;
+		}
+		last = expr;
+	}
+
+	if (p->policy_type == POLICY_KERN) {
+		if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+			goto err;
+		if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
+		    != 0)
+			goto err;
+	} else {
+		if (avrule_read_list(p, &node->avtrue_list, fp))
+			goto err;
+		if (avrule_read_list(p, &node->avfalse_list, fp))
+			goto err;
+	}
+
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto err;
+		node->flags = le32_to_cpu(buf[0]);
+	}
+
+	return 0;
+      err:
+	cond_node_destroy(node);
+	free(node);
+	return -1;
+}
+
+int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
+{
+	cond_node_t *node, *last = NULL;
+	uint32_t buf[1];
+	int i, len, rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+
+	len = le32_to_cpu(buf[0]);
+
+	rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
+	if (rc)
+		goto err;
+
+	for (i = 0; i < len; i++) {
+		node = malloc(sizeof(cond_node_t));
+		if (!node)
+			goto err;
+		memset(node, 0, sizeof(cond_node_t));
+
+		if (cond_read_node(p, node, fp) != 0)
+			goto err;
+
+		if (i == 0) {
+			*list = node;
+		} else {
+			last->next = node;
+		}
+		last = node;
+	}
+	return 0;
+      err:
+	return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result 
+ */
+void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+		     struct sepol_av_decision *avd)
+{
+	avtab_ptr_t node;
+
+	if (!ctab || !key || !avd)
+		return;
+
+	for (node = avtab_search_node(ctab, key); node != NULL;
+	     node = avtab_search_node_next(node, key->specified)) {
+		if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
+		    (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
+			avd->allowed |= node->datum.data;
+		if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
+		    (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
+			/* Since a '0' in an auditdeny mask represents a 
+			 * permission we do NOT want to audit (dontaudit), we use
+			 * the '&' operand to ensure that all '0's in the mask
+			 * are retained (much unlike the allow and auditallow cases).
+			 */
+			avd->auditdeny &= node->datum.data;
+		if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
+		    (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
+			avd->auditallow |= node->datum.data;
+	}
+	return;
+}
+
+avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+				   cond_av_list_t * cond_list)
+{
+
+	cond_av_list_t *cur_av;
+
+	for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
+
+		if (cur_av->node->key.source_type == key->source_type &&
+		    cur_av->node->key.target_type == key->target_type &&
+		    cur_av->node->key.target_class == key->target_class)
+
+			return &cur_av->node->datum;
+
+	}
+	return NULL;
+
+}
diff --git a/libsepol/src/constraint.c b/libsepol/src/constraint.c
new file mode 100644
index 0000000..7154019
--- /dev/null
+++ b/libsepol/src/constraint.c
@@ -0,0 +1,47 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 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 <sepol/policydb/policydb.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask_types.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+int constraint_expr_init(constraint_expr_t * expr)
+{
+	memset(expr, 0, sizeof(*expr));
+	ebitmap_init(&expr->names);
+	if ((expr->type_names = malloc(sizeof(*expr->type_names))) == NULL) {
+		return -1;
+	}
+	type_set_init(expr->type_names);
+	return 0;
+}
+
+void constraint_expr_destroy(constraint_expr_t * expr)
+{
+	if (expr != NULL) {
+		ebitmap_destroy(&expr->names);
+		type_set_destroy(expr->type_names);
+		free(expr->type_names);
+		free(expr);
+	}
+}
diff --git a/libsepol/src/context.c b/libsepol/src/context.c
new file mode 100644
index 0000000..84dad34
--- /dev/null
+++ b/libsepol/src/context.c
@@ -0,0 +1,338 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include "context_internal.h"
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+#include "mls.h"
+
+/* ----- Compatibility ---- */
+int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+	return context_is_valid(p, c);
+}
+
+int sepol_check_context(const char *context)
+{
+
+	return sepol_context_to_sid((const sepol_security_context_t)context,
+				    strlen(context) + 1, NULL);
+}
+
+/* ---- End compatibility --- */
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int context_is_valid(const policydb_t * p, const context_struct_t * c)
+{
+
+	role_datum_t *role;
+	user_datum_t *usrdatum;
+	ebitmap_t types, roles;
+	int ret = 1;
+
+	ebitmap_init(&types);
+	ebitmap_init(&roles);
+	if (!c->role || c->role > p->p_roles.nprim)
+		return 0;
+
+	if (!c->user || c->user > p->p_users.nprim)
+		return 0;
+
+	if (!c->type || c->type > p->p_types.nprim)
+		return 0;
+
+	if (c->role != OBJECT_R_VAL) {
+		/*
+		 * Role must be authorized for the type.
+		 */
+		role = p->role_val_to_struct[c->role - 1];
+		if (!ebitmap_get_bit(&role->cache, c->type - 1))
+			/* role may not be associated with type */
+			return 0;
+
+		/*
+		 * User must be authorized for the role.
+		 */
+		usrdatum = p->user_val_to_struct[c->user - 1];
+		if (!usrdatum)
+			return 0;
+
+		if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
+			/* user may not be associated with role */
+			return 0;
+	}
+
+	if (!mls_context_isvalid(p, c))
+		return 0;
+
+	return ret;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size.  Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int context_to_string(sepol_handle_t * handle,
+		      const policydb_t * policydb,
+		      const context_struct_t * context,
+		      char **result, size_t * result_len)
+{
+
+	char *scontext = NULL;
+	size_t scontext_len = 0;
+	char *ptr;
+
+	/* Compute the size of the context. */
+	scontext_len +=
+	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
+	scontext_len +=
+	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
+	scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
+	scontext_len += mls_compute_context_len(policydb, context);
+
+	/* We must null terminate the string */
+	scontext_len += 1;
+
+	/* Allocate space for the context; caller must free this space. */
+	scontext = malloc(scontext_len);
+	if (!scontext)
+		goto omem;
+	scontext[scontext_len - 1] = '\0';
+
+	/*
+	 * Copy the user name, role name and type name into the context.
+	 */
+	ptr = scontext;
+	sprintf(ptr, "%s:%s:%s",
+		policydb->p_user_val_to_name[context->user - 1],
+		policydb->p_role_val_to_name[context->role - 1],
+		policydb->p_type_val_to_name[context->type - 1]);
+
+	ptr +=
+	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
+	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
+	    strlen(policydb->p_type_val_to_name[context->type - 1]);
+
+	mls_sid_to_context(policydb, context, &ptr);
+
+	*result = scontext;
+	*result_len = scontext_len;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not convert " "context to string");
+	free(scontext);
+	return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the given record
+ */
+int context_from_record(sepol_handle_t * handle,
+			const policydb_t * policydb,
+			context_struct_t ** cptr,
+			const sepol_context_t * record)
+{
+
+	context_struct_t *scontext = NULL;
+	user_datum_t *usrdatum;
+	role_datum_t *roldatum;
+	type_datum_t *typdatum;
+
+	/* Hashtab keys are not constant - suppress warnings */
+	char *user = strdup(sepol_context_get_user(record));
+	char *role = strdup(sepol_context_get_role(record));
+	char *type = strdup(sepol_context_get_type(record));
+	const char *mls = sepol_context_get_mls(record);
+
+	scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
+	if (!user || !role || !type || !scontext) {
+		ERR(handle, "out of memory");
+		goto err;
+	}
+	context_init(scontext);
+
+	/* User */
+	usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
+						   (hashtab_key_t) user);
+	if (!usrdatum) {
+		ERR(handle, "user %s is not defined", user);
+		goto err_destroy;
+	}
+	scontext->user = usrdatum->s.value;
+
+	/* Role */
+	roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
+						   (hashtab_key_t) role);
+	if (!roldatum) {
+		ERR(handle, "role %s is not defined", role);
+		goto err_destroy;
+	}
+	scontext->role = roldatum->s.value;
+
+	/* Type */
+	typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
+						   (hashtab_key_t) type);
+	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
+		ERR(handle, "type %s is not defined", type);
+		goto err_destroy;
+	}
+	scontext->type = typdatum->s.value;
+
+	/* MLS */
+	if (mls && !policydb->mls) {
+		ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
+		    mls);
+		goto err_destroy;
+	} else if (!mls && policydb->mls) {
+		ERR(handle, "MLS is enabled, but no MLS context found");
+		goto err_destroy;
+	}
+	if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
+		goto err_destroy;
+
+	/* Validity check */
+	if (!context_is_valid(policydb, scontext)) {
+		if (mls) {
+			ERR(handle,
+			    "invalid security context: \"%s:%s:%s:%s\"",
+			    user, role, type, mls);
+		} else {
+			ERR(handle,
+			    "invalid security context: \"%s:%s:%s\"",
+			    user, role, type);
+		}
+		goto err_destroy;
+	}
+
+	*cptr = scontext;
+	free(user);
+	free(type);
+	free(role);
+	return STATUS_SUCCESS;
+
+      err_destroy:
+	errno = EINVAL;
+	context_destroy(scontext);
+
+      err:
+	free(scontext);
+	free(user);
+	free(type);
+	free(role);
+	ERR(handle, "could not create context structure");
+	return STATUS_ERR;
+}
+
+/*
+ * Create a record from the given context structure
+ */
+int context_to_record(sepol_handle_t * handle,
+		      const policydb_t * policydb,
+		      const context_struct_t * context,
+		      sepol_context_t ** record)
+{
+
+	sepol_context_t *tmp_record = NULL;
+	char *mls = NULL;
+
+	if (sepol_context_create(handle, &tmp_record) < 0)
+		goto err;
+
+	if (sepol_context_set_user(handle, tmp_record,
+				   policydb->p_user_val_to_name[context->user -
+								1]) < 0)
+		goto err;
+
+	if (sepol_context_set_role(handle, tmp_record,
+				   policydb->p_role_val_to_name[context->role -
+								1]) < 0)
+		goto err;
+
+	if (sepol_context_set_type(handle, tmp_record,
+				   policydb->p_type_val_to_name[context->type -
+								1]) < 0)
+		goto err;
+
+	if (policydb->mls) {
+		if (mls_to_string(handle, policydb, context, &mls) < 0)
+			goto err;
+
+		if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
+			goto err;
+	}
+
+	free(mls);
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not create context record");
+	sepol_context_free(tmp_record);
+	free(mls);
+	return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the provided string.
+ */
+int context_from_string(sepol_handle_t * handle,
+			const policydb_t * policydb,
+			context_struct_t ** cptr,
+			const char *con_str, size_t con_str_len)
+{
+
+	char *con_cpy = NULL;
+	sepol_context_t *ctx_record = NULL;
+
+	/* sepol_context_from_string expects a NULL-terminated string */
+	con_cpy = malloc(con_str_len + 1);
+	if (!con_cpy)
+		goto omem;
+	memcpy(con_cpy, con_str, con_str_len);
+	con_cpy[con_str_len] = '\0';
+
+	if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
+		goto err;
+
+	/* Now create from the data structure */
+	if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
+		goto err;
+
+	free(con_cpy);
+	sepol_context_free(ctx_record);
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not create context structure");
+	free(con_cpy);
+	sepol_context_free(ctx_record);
+	return STATUS_ERR;
+}
+
+int sepol_context_check(sepol_handle_t * handle,
+			const sepol_policydb_t * policydb,
+			const sepol_context_t * context)
+{
+
+	context_struct_t *con = NULL;
+	int ret = context_from_record(handle, &policydb->p, &con, context);
+	context_destroy(con);
+	free(con);
+	return ret;
+}
diff --git a/libsepol/src/context.h b/libsepol/src/context.h
new file mode 100644
index 0000000..d25ca8a
--- /dev/null
+++ b/libsepol/src/context.h
@@ -0,0 +1,37 @@
+#ifndef _SEPOL_INTERNAL_CONTEXT_H_
+#define _SEPOL_INTERNAL_CONTEXT_H_
+
+#include <stddef.h>
+#include "context_internal.h"
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/handle.h>
+
+/* Create a context structure from high level representation */
+extern int context_from_record(sepol_handle_t * handle,
+			       const policydb_t * policydb,
+			       context_struct_t ** cptr,
+			       const sepol_context_t * data);
+
+extern int context_to_record(sepol_handle_t * handle,
+			     const policydb_t * policydb,
+			     const context_struct_t * context,
+			     sepol_context_t ** record);
+
+/* Create a context structure from string representation */
+extern int context_from_string(sepol_handle_t * handle,
+			       const policydb_t * policydb,
+			       context_struct_t ** cptr,
+			       const char *con_str, size_t con_str_len);
+
+/* Check if the provided context is valid for this policy */
+extern int context_is_valid(const policydb_t * policydb,
+			    const context_struct_t * context);
+
+/* Extract the context as string */
+extern int context_to_string(sepol_handle_t * handle,
+			     const policydb_t * policydb,
+			     const context_struct_t * context,
+			     char **result, size_t * result_len);
+
+#endif
diff --git a/libsepol/src/context_internal.h b/libsepol/src/context_internal.h
new file mode 100644
index 0000000..7987c1c
--- /dev/null
+++ b/libsepol/src/context_internal.h
@@ -0,0 +1,19 @@
+#ifndef _SEPOL_CONTEXT_INTERNAL_H_
+#define _SEPOL_CONTEXT_INTERNAL_H_
+
+#include <sepol/context_record.h>
+#include "dso.h"
+
+hidden_proto(sepol_context_clone)
+    hidden_proto(sepol_context_create)
+    hidden_proto(sepol_context_free)
+    hidden_proto(sepol_context_from_string)
+    hidden_proto(sepol_context_get_mls)
+    hidden_proto(sepol_context_get_role)
+    hidden_proto(sepol_context_get_type)
+    hidden_proto(sepol_context_get_user)
+    hidden_proto(sepol_context_set_mls)
+    hidden_proto(sepol_context_set_role)
+    hidden_proto(sepol_context_set_type)
+    hidden_proto(sepol_context_set_user)
+#endif
diff --git a/libsepol/src/context_record.c b/libsepol/src/context_record.c
new file mode 100644
index 0000000..ac2884a
--- /dev/null
+++ b/libsepol/src/context_record.c
@@ -0,0 +1,324 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_context {
+
+	/* Selinux user */
+	char *user;
+
+	/* Selinux role */
+	char *role;
+
+	/* Selinux type */
+	char *type;
+
+	/* MLS */
+	char *mls;
+};
+
+/* User */
+const char *sepol_context_get_user(const sepol_context_t * con)
+{
+
+	return con->user;
+}
+
+hidden_def(sepol_context_get_user)
+
+int sepol_context_set_user(sepol_handle_t * handle,
+			   sepol_context_t * con, const char *user)
+{
+
+	char *tmp_user = strdup(user);
+	if (!tmp_user) {
+		ERR(handle, "out of memory, could not set "
+		    "context user to %s", user);
+		return STATUS_ERR;
+	}
+
+	free(con->user);
+	con->user = tmp_user;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_user)
+
+/* Role */
+const char *sepol_context_get_role(const sepol_context_t * con)
+{
+
+	return con->role;
+}
+
+hidden_def(sepol_context_get_role)
+
+int sepol_context_set_role(sepol_handle_t * handle,
+			   sepol_context_t * con, const char *role)
+{
+
+	char *tmp_role = strdup(role);
+	if (!tmp_role) {
+		ERR(handle, "out of memory, could not set "
+		    "context role to %s", role);
+		return STATUS_ERR;
+	}
+	free(con->role);
+	con->role = tmp_role;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_role)
+
+/* Type */
+const char *sepol_context_get_type(const sepol_context_t * con)
+{
+
+	return con->type;
+}
+
+hidden_def(sepol_context_get_type)
+
+int sepol_context_set_type(sepol_handle_t * handle,
+			   sepol_context_t * con, const char *type)
+{
+
+	char *tmp_type = strdup(type);
+	if (!tmp_type) {
+		ERR(handle, "out of memory, could not set "
+		    "context type to %s", type);
+		return STATUS_ERR;
+	}
+	free(con->type);
+	con->type = tmp_type;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_type)
+
+/* MLS */
+const char *sepol_context_get_mls(const sepol_context_t * con)
+{
+
+	return con->mls;
+}
+
+hidden_def(sepol_context_get_mls)
+
+int sepol_context_set_mls(sepol_handle_t * handle,
+			  sepol_context_t * con, const char *mls)
+{
+
+	char *tmp_mls = strdup(mls);
+	if (!tmp_mls) {
+		ERR(handle, "out of memory, could not set "
+		    "MLS fields to %s", mls);
+		return STATUS_ERR;
+	}
+	free(con->mls);
+	con->mls = tmp_mls;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_mls)
+
+/* Create */
+int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
+{
+
+	sepol_context_t *con =
+	    (sepol_context_t *) malloc(sizeof(sepol_context_t));
+
+	if (!con) {
+		ERR(handle, "out of memory, could not " "create context\n");
+		return STATUS_ERR;
+	}
+
+	con->user = NULL;
+	con->role = NULL;
+	con->type = NULL;
+	con->mls = NULL;
+	*con_ptr = con;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_create)
+
+/* Deep copy clone */
+int sepol_context_clone(sepol_handle_t * handle,
+			const sepol_context_t * con, sepol_context_t ** con_ptr)
+{
+
+	sepol_context_t *new_con = NULL;
+
+	if (!con) {
+		*con_ptr = NULL;
+		return 0;
+	}
+	  
+	if (sepol_context_create(handle, &new_con) < 0)
+		goto err;
+
+	if (!(new_con->user = strdup(con->user)))
+		goto omem;
+
+	if (!(new_con->role = strdup(con->role)))
+		goto omem;
+
+	if (!(new_con->type = strdup(con->type)))
+		goto omem;
+
+	if (con->mls && !(new_con->mls = strdup(con->mls)))
+		goto omem;
+
+	*con_ptr = new_con;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not clone context record");
+	sepol_context_free(new_con);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_context_clone)
+
+/* Destroy */
+void sepol_context_free(sepol_context_t * con)
+{
+
+	if (!con)
+		return;
+
+	free(con->user);
+	free(con->role);
+	free(con->type);
+	free(con->mls);
+	free(con);
+}
+
+hidden_def(sepol_context_free)
+
+int sepol_context_from_string(sepol_handle_t * handle,
+			      const char *str, sepol_context_t ** con)
+{
+
+	char *tmp = NULL, *low, *high;
+	sepol_context_t *tmp_con = NULL;
+
+	if (!strcmp(str, "<<none>>")) {
+		*con = NULL;
+		return STATUS_SUCCESS;
+	}
+
+	if (sepol_context_create(handle, &tmp_con) < 0)
+		goto err;
+
+	/* Working copy context */
+	tmp = strdup(str);
+	if (!tmp) {
+		ERR(handle, "out of memory");
+		goto err;
+	}
+	low = tmp;
+
+	/* Then, break it into its components */
+
+	/* User */
+	if (!(high = strchr(low, ':')))
+		goto mcontext;
+	else
+		*high++ = '\0';
+	if (sepol_context_set_user(handle, tmp_con, low) < 0)
+		goto err;
+	low = high;
+
+	/* Role */
+	if (!(high = strchr(low, ':')))
+		goto mcontext;
+	else
+		*high++ = '\0';
+	if (sepol_context_set_role(handle, tmp_con, low) < 0)
+		goto err;
+	low = high;
+
+	/* Type, and possibly MLS */
+	if (!(high = strchr(low, ':'))) {
+		if (sepol_context_set_type(handle, tmp_con, low) < 0)
+			goto err;
+	} else {
+		*high++ = '\0';
+		if (sepol_context_set_type(handle, tmp_con, low) < 0)
+			goto err;
+		low = high;
+		if (sepol_context_set_mls(handle, tmp_con, low) < 0)
+			goto err;
+	}
+
+	free(tmp);
+	*con = tmp_con;
+
+	return STATUS_SUCCESS;
+
+      mcontext:
+	errno = EINVAL;
+	ERR(handle, "malformed context \"%s\"", str);
+
+      err:
+	ERR(handle, "could not construct context from string");
+	free(tmp);
+	sepol_context_free(tmp_con);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_context_from_string)
+
+int sepol_context_to_string(sepol_handle_t * handle,
+			    const sepol_context_t * con, char **str_ptr)
+{
+
+	int rc;
+	const int user_sz = strlen(con->user);
+	const int role_sz = strlen(con->role);
+	const int type_sz = strlen(con->type);
+	const int mls_sz = (con->mls) ? strlen(con->mls) : 0;
+	const int total_sz = user_sz + role_sz + type_sz +
+	    mls_sz + ((con->mls) ? 3 : 2);
+
+	char *str = (char *)malloc(total_sz + 1);
+	if (!str)
+		goto omem;
+
+	if (con->mls) {
+		rc = snprintf(str, total_sz + 1, "%s:%s:%s:%s",
+			      con->user, con->role, con->type, con->mls);
+		if (rc < 0 || (rc >= total_sz + 1)) {
+			ERR(handle, "print error");
+			goto err;
+		}
+	} else {
+		rc = snprintf(str, total_sz + 1, "%s:%s:%s",
+			      con->user, con->role, con->type);
+		if (rc < 0 || (rc >= total_sz + 1)) {
+			ERR(handle, "print error");
+			goto err;
+		}
+	}
+
+	*str_ptr = str;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not convert context to string");
+	free(str);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/debug.c b/libsepol/src/debug.c
new file mode 100644
index 0000000..db57090
--- /dev/null
+++ b/libsepol/src/debug.c
@@ -0,0 +1,87 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "handle.h"
+#include "debug.h"
+
+/* Deprecated */
+struct sepol_handle sepol_compat_handle = {
+	.msg_callback = sepol_msg_default_handler,
+	.msg_callback_arg = NULL,
+};
+
+void sepol_debug(int on)
+{
+	sepol_compat_handle.msg_callback = (on) ?
+	    sepol_msg_default_handler : NULL;
+}
+
+/* End deprecated */
+
+int sepol_msg_get_level(sepol_handle_t * handle)
+{
+	return handle->msg_level;
+}
+
+hidden_def(sepol_msg_get_level)
+
+const char *sepol_msg_get_channel(sepol_handle_t * handle)
+{
+	return handle->msg_channel;
+}
+
+hidden_def(sepol_msg_get_channel)
+
+const char *sepol_msg_get_fname(sepol_handle_t * handle)
+{
+	return handle->msg_fname;
+}
+
+hidden_def(sepol_msg_get_fname)
+#ifdef __GNUC__
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+void hidden sepol_msg_default_handler(void *varg __attribute__ ((unused)),
+				      sepol_handle_t * handle,
+				      const char *fmt, ...)
+{
+
+	FILE *stream = NULL;
+
+	switch (sepol_msg_get_level(handle)) {
+
+	case SEPOL_MSG_ERR:
+	case SEPOL_MSG_WARN:
+		stream = stderr;
+		break;
+	case SEPOL_MSG_INFO:
+	default:
+		stream = stdout;
+		break;
+	}
+
+	fprintf(stream, "%s.%s: ",
+		sepol_msg_get_channel(handle), sepol_msg_get_fname(handle));
+
+	va_list ap;
+	va_start(ap, fmt);
+	vfprintf(stream, fmt, ap);
+	va_end(ap);
+
+	fprintf(stream, "\n");
+}
+
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+				   __attribute__ ((format(printf, 3, 4)))
+#endif
+				   void (*msg_callback) (void *varg,
+							 sepol_handle_t *
+							 handle,
+							 const char *fmt, ...),
+				   void *msg_callback_arg)
+{
+
+	handle->msg_callback = msg_callback;
+	handle->msg_callback_arg = msg_callback_arg;
+}
diff --git a/libsepol/src/debug.h b/libsepol/src/debug.h
new file mode 100644
index 0000000..56b397b
--- /dev/null
+++ b/libsepol/src/debug.h
@@ -0,0 +1,74 @@
+/*
+ * 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
+ */
+
+#ifndef _SEPOL_INTERNAL_DEBUG_H_
+#define _SEPOL_INTERNAL_DEBUG_H_
+
+#include <stdio.h>
+#include <sepol/debug.h>
+#include "dso.h"
+#include "handle.h"
+
+#define STATUS_SUCCESS 0
+#define STATUS_ERR -1
+#define STATUS_NODATA 1
+
+/* FIXME: this needs to become a real function. Declaring variables
+ * in a macro is _evil_ as it can shadow other variables in local scope.
+ * The variable h has been renamed to _sepol_h to reduce this chance, but
+ * it is still wrong.
+ */
+#define msg_write(handle_arg, level_arg,			   \
+		  channel_arg, func_arg, ...) do {		   \
+		sepol_handle_t *_sepol_h = (handle_arg) ?: &sepol_compat_handle; \
+		if (_sepol_h->msg_callback) {			   \
+			_sepol_h->msg_fname = func_arg;		   \
+			_sepol_h->msg_channel = channel_arg;	   \
+			_sepol_h->msg_level = level_arg;	   \
+								   \
+			_sepol_h->msg_callback(			   \
+				_sepol_h->msg_callback_arg,	   \
+				_sepol_h, __VA_ARGS__);		   \
+		}                                                  \
+	} while(0)
+
+#define ERR(handle, ...) \
+	msg_write(handle, SEPOL_MSG_ERR, "libsepol", \
+	__FUNCTION__, __VA_ARGS__)
+
+#define INFO(handle, ...) \
+	msg_write(handle, SEPOL_MSG_INFO, "libsepol", \
+	__FUNCTION__, __VA_ARGS__)
+
+#define WARN(handle, ...) \
+	msg_write(handle, SEPOL_MSG_WARN, "libsepol", \
+	__FUNCTION__, __VA_ARGS__)
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 3, 4)))
+#endif
+extern void hidden sepol_msg_default_handler(void *varg,
+					     sepol_handle_t * msg,
+					     const char *fmt, ...);
+
+extern struct sepol_handle sepol_compat_handle;
+
+hidden_proto(sepol_msg_get_channel)
+    hidden_proto(sepol_msg_get_fname)
+    hidden_proto(sepol_msg_get_level)
+#endif
diff --git a/libsepol/src/dso.h b/libsepol/src/dso.h
new file mode 100644
index 0000000..a06e349
--- /dev/null
+++ b/libsepol/src/dso.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H	1
+
+#if !defined(SHARED) || defined(ANDROID)
+    #define DISABLE_SYMVER 1
+#endif
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal)	\
+     extern __typeof (fct) internal;	\
+     extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c
new file mode 100644
index 0000000..58f2fc4
--- /dev/null
+++ b/libsepol/src/ebitmap.c
@@ -0,0 +1,466 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/* 
+ * Implementation of the extensible bitmap type.
+ */
+
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "private.h"
+
+int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2)
+{
+	ebitmap_node_t *n1, *n2, *new, *prev;
+
+	ebitmap_init(dst);
+
+	n1 = e1->node;
+	n2 = e2->node;
+	prev = 0;
+	while (n1 || n2) {
+		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+		if (!new) {
+			ebitmap_destroy(dst);
+			return -ENOMEM;
+		}
+		memset(new, 0, sizeof(ebitmap_node_t));
+		if (n1 && n2 && n1->startbit == n2->startbit) {
+			new->startbit = n1->startbit;
+			new->map = n1->map | n2->map;
+			n1 = n1->next;
+			n2 = n2->next;
+		} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
+			new->startbit = n1->startbit;
+			new->map = n1->map;
+			n1 = n1->next;
+		} else {
+			new->startbit = n2->startbit;
+			new->map = n2->map;
+			n2 = n2->next;
+		}
+
+		new->next = 0;
+		if (prev)
+			prev->next = new;
+		else
+			dst->node = new;
+		prev = new;
+	}
+
+	dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
+	return 0;
+}
+
+int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1)
+{
+	ebitmap_t tmp;
+
+	if (ebitmap_or(&tmp, dst, e1))
+		return -1;
+	ebitmap_destroy(dst);
+	dst->node = tmp.node;
+	dst->highbit = tmp.highbit;
+
+	return 0;
+}
+
+int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2)
+{
+	unsigned int i, length = min(ebitmap_length(e1), ebitmap_length(e2));
+	ebitmap_init(dst);
+	for (i=0; i < length; i++) {
+		if (ebitmap_get_bit(e1, i) && ebitmap_get_bit(e2, i)) {
+			int rc = ebitmap_set_bit(dst, i, 1);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2)
+{
+	unsigned int i, length = max(ebitmap_length(e1), ebitmap_length(e2));
+	ebitmap_init(dst);
+	for (i=0; i < length; i++) {
+		int val = ebitmap_get_bit(e1, i) ^ ebitmap_get_bit(e2, i);
+		int rc = ebitmap_set_bit(dst, i, val);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit)
+{
+	unsigned int i;
+	ebitmap_init(dst);
+	for (i=0; i < maxbit; i++) {
+		int val = ebitmap_get_bit(e1, i);
+		int rc = ebitmap_set_bit(dst, i, !val);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit)
+{
+	ebitmap_t e3;
+	ebitmap_init(dst);
+	int rc = ebitmap_not(&e3, e2, maxbit);
+	if (rc < 0)
+		return rc;
+	rc = ebitmap_and(dst, e1, &e3);
+	ebitmap_destroy(&e3);
+	if (rc < 0)
+		return rc;
+	return 0;
+}
+
+unsigned int ebitmap_cardinality(ebitmap_t *e1)
+{
+	unsigned int i, count = 0;
+	for (i=ebitmap_startbit(e1); i < ebitmap_length(e1); i++)
+		if (ebitmap_get_bit(e1, i))
+			count++;
+	return count;
+}
+
+int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2)
+{
+	if (ebitmap_cmp(e1, e2))
+		return 0;
+	ebitmap_t tmp;
+	int rc = ebitmap_xor(&tmp, e1, e2);
+	if (rc < 0)
+		return -1;
+	int distance = ebitmap_cardinality(&tmp);
+	ebitmap_destroy(&tmp);
+	return distance;
+}
+
+int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+	ebitmap_node_t *n1, *n2;
+
+	if (e1->highbit != e2->highbit)
+		return 0;
+
+	n1 = e1->node;
+	n2 = e2->node;
+	while (n1 && n2 &&
+	       (n1->startbit == n2->startbit) && (n1->map == n2->map)) {
+		n1 = n1->next;
+		n2 = n2->next;
+	}
+
+	if (n1 || n2)
+		return 0;
+
+	return 1;
+}
+
+int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src)
+{
+	ebitmap_node_t *n, *new, *prev;
+
+	ebitmap_init(dst);
+	n = src->node;
+	prev = 0;
+	while (n) {
+		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+		if (!new) {
+			ebitmap_destroy(dst);
+			return -ENOMEM;
+		}
+		memset(new, 0, sizeof(ebitmap_node_t));
+		new->startbit = n->startbit;
+		new->map = n->map;
+		new->next = 0;
+		if (prev)
+			prev->next = new;
+		else
+			dst->node = new;
+		prev = new;
+		n = n->next;
+	}
+
+	dst->highbit = src->highbit;
+	return 0;
+}
+
+int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+	ebitmap_node_t *n1, *n2;
+
+	if (e1->highbit < e2->highbit)
+		return 0;
+
+	n1 = e1->node;
+	n2 = e2->node;
+	while (n1 && n2 && (n1->startbit <= n2->startbit)) {
+		if (n1->startbit < n2->startbit) {
+			n1 = n1->next;
+			continue;
+		}
+		if ((n1->map & n2->map) != n2->map)
+			return 0;
+
+		n1 = n1->next;
+		n2 = n2->next;
+	}
+
+	if (n2)
+		return 0;
+
+	return 1;
+}
+
+int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2)
+{
+	ebitmap_node_t *n1 = e1->node;
+	ebitmap_node_t *n2 = e2->node;
+
+	while (n1 && n2) {
+		if (n1->startbit < n2->startbit) {
+			n1 = n1->next;
+		} else if (n2->startbit < n1->startbit) {
+			n2 = n2->next;
+		} else {
+			if (n1->map & n2->map) {
+				return 1;
+			}
+			n1 = n1->next;
+			n2 = n2->next;
+		}
+	}
+
+	return 0;
+}
+
+int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
+{
+	ebitmap_node_t *n;
+
+	if (e->highbit < bit)
+		return 0;
+
+	n = e->node;
+	while (n && (n->startbit <= bit)) {
+		if ((n->startbit + MAPSIZE) > bit) {
+			if (n->map & (MAPBIT << (bit - n->startbit)))
+				return 1;
+			else
+				return 0;
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
+int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value)
+{
+	ebitmap_node_t *n, *prev, *new;
+	uint32_t startbit = bit & ~(MAPSIZE - 1);
+	uint32_t highbit = startbit + MAPSIZE;
+
+	if (highbit == 0) {
+		ERR(NULL, "bitmap overflow, bit 0x%x", bit);
+		return -EINVAL;
+	}
+
+	prev = 0;
+	n = e->node;
+	while (n && n->startbit <= bit) {
+		if ((n->startbit + MAPSIZE) > bit) {
+			if (value) {
+				n->map |= (MAPBIT << (bit - n->startbit));
+			} else {
+				n->map &= ~(MAPBIT << (bit - n->startbit));
+				if (!n->map) {
+					/* drop this node from the bitmap */
+
+					if (!n->next) {
+						/*
+						 * this was the highest map
+						 * within the bitmap
+						 */
+						if (prev)
+							e->highbit =
+							    prev->startbit +
+							    MAPSIZE;
+						else
+							e->highbit = 0;
+					}
+					if (prev)
+						prev->next = n->next;
+					else
+						e->node = n->next;
+
+					free(n);
+				}
+			}
+			return 0;
+		}
+		prev = n;
+		n = n->next;
+	}
+
+	if (!value)
+		return 0;
+
+	new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+	if (!new)
+		return -ENOMEM;
+	memset(new, 0, sizeof(ebitmap_node_t));
+
+	new->startbit = startbit;
+	new->map = (MAPBIT << (bit - new->startbit));
+
+	if (!n) {
+		/* this node will be the highest map within the bitmap */
+		e->highbit = highbit;
+	}
+
+	if (prev) {
+		new->next = prev->next;
+		prev->next = new;
+	} else {
+		new->next = e->node;
+		e->node = new;
+	}
+
+	return 0;
+}
+
+void ebitmap_destroy(ebitmap_t * e)
+{
+	ebitmap_node_t *n, *temp;
+
+	if (!e)
+		return;
+
+	n = e->node;
+	while (n) {
+		temp = n;
+		n = n->next;
+		free(temp);
+	}
+
+	e->highbit = 0;
+	e->node = 0;
+	return;
+}
+
+int ebitmap_read(ebitmap_t * e, void *fp)
+{
+	int rc;
+	ebitmap_node_t *n, *l;
+	uint32_t buf[3], mapsize, count, i;
+	uint64_t map;
+
+	ebitmap_init(e);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+	if (rc < 0)
+		goto bad;
+
+	mapsize = le32_to_cpu(buf[0]);
+	e->highbit = le32_to_cpu(buf[1]);
+	count = le32_to_cpu(buf[2]);
+
+	if (mapsize != MAPSIZE) {
+		printf
+		    ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n",
+		     mapsize, MAPSIZE, e->highbit);
+		goto bad;
+	}
+	if (!e->highbit) {
+		e->node = NULL;
+		goto ok;
+	}
+	if (e->highbit & (MAPSIZE - 1)) {
+		printf
+		    ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n",
+		     e->highbit, MAPSIZE);
+		goto bad;
+	}
+	l = NULL;
+	for (i = 0; i < count; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0) {
+			printf("security: ebitmap: truncated map\n");
+			goto bad;
+		}
+		n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+		if (!n) {
+			printf("security: ebitmap: out of memory\n");
+			rc = -ENOMEM;
+			goto bad;
+		}
+		memset(n, 0, sizeof(ebitmap_node_t));
+
+		n->startbit = le32_to_cpu(buf[0]);
+
+		if (n->startbit & (MAPSIZE - 1)) {
+			printf
+			    ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n",
+			     n->startbit, MAPSIZE);
+			goto bad_free;
+		}
+		if (n->startbit > (e->highbit - MAPSIZE)) {
+			printf
+			    ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n",
+			     n->startbit, (e->highbit - MAPSIZE));
+			goto bad_free;
+		}
+		rc = next_entry(&map, fp, sizeof(uint64_t));
+		if (rc < 0) {
+			printf("security: ebitmap: truncated map\n");
+			goto bad_free;
+		}
+		n->map = le64_to_cpu(map);
+
+		if (!n->map) {
+			printf
+			    ("security: ebitmap: null map in ebitmap (startbit %d)\n",
+			     n->startbit);
+			goto bad_free;
+		}
+		if (l) {
+			if (n->startbit <= l->startbit) {
+				printf
+				    ("security: ebitmap: start bit %d comes after start bit %d\n",
+				     n->startbit, l->startbit);
+				goto bad_free;
+			}
+			l->next = n;
+		} else
+			e->node = n;
+
+		l = n;
+	}
+
+      ok:
+	rc = 0;
+      out:
+	return rc;
+      bad_free:
+	free(n);
+      bad:
+	if (!rc)
+		rc = -EINVAL;
+	ebitmap_destroy(e);
+	goto out;
+}
+
+/* FLASK */
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
new file mode 100644
index 0000000..9cb7965
--- /dev/null
+++ b/libsepol/src/expand.c
@@ -0,0 +1,3458 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *          Jason Tang <jtang@tresys.com>
+ *	    Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ *  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 "context.h"
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+#include "private.h"
+
+typedef struct expand_state {
+	int verbose;
+	uint32_t *typemap;
+	uint32_t *boolmap;
+	uint32_t *rolemap;
+	uint32_t *usermap;
+	policydb_t *base;
+	policydb_t *out;
+	sepol_handle_t *handle;
+	int expand_neverallow;
+} expand_state_t;
+
+static void expand_state_init(expand_state_t * state)
+{
+	memset(state, 0, sizeof(expand_state_t));
+}
+
+static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
+{
+	unsigned int i;
+	ebitmap_node_t *tnode;
+	ebitmap_init(dst);
+
+	ebitmap_for_each_bit(src, tnode, i) {
+		if (!ebitmap_node_get_bit(tnode, i))
+			continue;
+		if (!map[i])
+			continue;
+		if (ebitmap_set_bit(dst, map[i] - 1, 1))
+			return -1;
+	}
+	return 0;
+}
+
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id, *new_id;
+	type_datum_t *type, *new_type;
+	expand_state_t *state;
+
+	id = (char *)key;
+	type = (type_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if ((type->flavor == TYPE_TYPE && !type->primary)
+	    || type->flavor == TYPE_ALIAS) {
+		/* aliases are handled later */
+		return 0;
+	}
+	if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying type or attribute %s", id);
+
+	new_id = strdup(id);
+	if (new_id == NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	new_type = (type_datum_t *) malloc(sizeof(type_datum_t));
+	if (!new_type) {
+		ERR(state->handle, "Out of memory!");
+		free(new_id);
+		return SEPOL_ENOMEM;
+	}
+	memset(new_type, 0, sizeof(type_datum_t));
+
+	new_type->flavor = type->flavor;
+	new_type->flags = type->flags;
+	new_type->s.value = ++state->out->p_types.nprim;
+	if (new_type->s.value > UINT16_MAX) {
+		free(new_id);
+		free(new_type);
+		ERR(state->handle, "type space overflow");
+		return -1;
+	}
+	new_type->primary = 1;
+	state->typemap[type->s.value - 1] = new_type->s.value;
+
+	ret = hashtab_insert(state->out->p_types.table,
+			     (hashtab_key_t) new_id,
+			     (hashtab_datum_t) new_type);
+	if (ret) {
+		free(new_id);
+		free(new_type);
+		ERR(state->handle, "hashtab overflow");
+		return -1;
+	}
+
+	if (new_type->flags & TYPE_FLAGS_PERMISSIVE)
+		if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) {
+			ERR(state->handle, "Out of memory!\n");
+			return -1;
+		}
+
+	return 0;
+}
+
+static int attr_convert_callback(hashtab_key_t key, hashtab_datum_t datum,
+				 void *data)
+{
+	char *id;
+	type_datum_t *type, *new_type;
+	expand_state_t *state;
+	ebitmap_t tmp_union;
+
+	id = (char *)key;
+	type = (type_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (type->flavor != TYPE_ATTRIB)
+		return 0;
+
+	if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "converting attribute %s", id);
+
+	new_type = hashtab_search(state->out->p_types.table, id);
+	if (!new_type) {
+		ERR(state->handle, "attribute %s vanished!", id);
+		return -1;
+	}
+	if (map_ebitmap(&type->types, &tmp_union, state->typemap)) {
+		ERR(state->handle, "out of memory");
+		return -1;
+	}
+
+	/* then union tmp_union onto &new_type->types */
+	if (ebitmap_union(&new_type->types, &tmp_union)) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	ebitmap_destroy(&tmp_union);
+
+	return 0;
+}
+
+static int perm_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id, *new_id;
+	symtab_t *s;
+	perm_datum_t *perm, *new_perm;
+
+	id = key;
+	perm = (perm_datum_t *) datum;
+	s = (symtab_t *) data;
+
+	new_perm = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+	if (!new_perm) {
+		return -1;
+	}
+	memset(new_perm, 0, sizeof(perm_datum_t));
+
+	new_id = strdup(id);
+	if (!new_id) {
+		free(new_perm);
+		return -1;
+	}
+
+	new_perm->s.value = perm->s.value;
+	s->nprim++;
+
+	ret = hashtab_insert(s->table, new_id, (hashtab_datum_t *) new_perm);
+	if (ret) {
+		free(new_id);
+		free(new_perm);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int common_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+				void *data)
+{
+	int ret;
+	char *id, *new_id;
+	common_datum_t *common, *new_common;
+	expand_state_t *state;
+
+	id = (char *)key;
+	common = (common_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (state->verbose)
+		INFO(state->handle, "copying common %s", id);
+
+	new_common = (common_datum_t *) malloc(sizeof(common_datum_t));
+	if (!new_common) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	memset(new_common, 0, sizeof(common_datum_t));
+	if (symtab_init(&new_common->permissions, PERM_SYMTAB_SIZE)) {
+		ERR(state->handle, "Out of memory!");
+		free(new_common);
+		return -1;
+	}
+
+	new_id = strdup(id);
+	if (!new_id) {
+		ERR(state->handle, "Out of memory!");
+		/* free memory created by symtab_init first, then free new_common */
+		symtab_destroy(&new_common->permissions);
+		free(new_common);
+		return -1;
+	}
+
+	new_common->s.value = common->s.value;
+	state->out->p_commons.nprim++;
+
+	ret =
+	    hashtab_insert(state->out->p_commons.table, new_id,
+			   (hashtab_datum_t *) new_common);
+	if (ret) {
+		ERR(state->handle, "hashtab overflow");
+		free(new_common);
+		free(new_id);
+		return -1;
+	}
+
+	if (hashtab_map
+	    (common->permissions.table, perm_copy_callback,
+	     &new_common->permissions)) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int constraint_node_clone(constraint_node_t ** dst,
+				 constraint_node_t * src,
+				 expand_state_t * state)
+{
+	constraint_node_t *new_con = NULL, *last_new_con = NULL;
+	constraint_expr_t *new_expr = NULL;
+	*dst = NULL;
+	while (src != NULL) {
+		constraint_expr_t *expr, *expr_l = NULL;
+		new_con =
+		    (constraint_node_t *) malloc(sizeof(constraint_node_t));
+		if (!new_con) {
+			goto out_of_mem;
+		}
+		memset(new_con, 0, sizeof(constraint_node_t));
+		new_con->permissions = src->permissions;
+		for (expr = src->expr; expr; expr = expr->next) {
+			if ((new_expr = calloc(1, sizeof(*new_expr))) == NULL) {
+				goto out_of_mem;
+			}
+			if (constraint_expr_init(new_expr) == -1) {
+				goto out_of_mem;
+			}
+			new_expr->expr_type = expr->expr_type;
+			new_expr->attr = expr->attr;
+			new_expr->op = expr->op;
+			if (new_expr->expr_type == CEXPR_NAMES) {
+				if (new_expr->attr & CEXPR_TYPE) {
+					/*
+					 * Copy over constraint policy source types and/or
+					 * attributes for sepol_compute_av_reason_buffer(3)
+					 * so that utilities can analyse constraint errors.
+					 */
+					if (map_ebitmap(&expr->type_names->types,
+							&new_expr->type_names->types,
+							state->typemap)) {
+						ERR(NULL, "Failed to map type_names->types");
+						goto out_of_mem;
+					}
+					/* Type sets require expansion and conversion. */
+					if (expand_convert_type_set(state->out,
+								    state->
+								    typemap,
+								    expr->
+								    type_names,
+								    &new_expr->
+								    names, 1)) {
+						goto out_of_mem;
+					}
+				} else if (new_expr->attr & CEXPR_ROLE) {
+					if (map_ebitmap(&expr->names, &new_expr->names, state->rolemap)) {
+						goto out_of_mem;
+					}
+				} else if (new_expr->attr & CEXPR_USER) {
+					if (map_ebitmap(&expr->names, &new_expr->names, state->usermap)) {
+						goto out_of_mem;
+					}
+				} else {
+					/* Other kinds of sets do not. */
+					if (ebitmap_cpy(&new_expr->names,
+							&expr->names)) {
+						goto out_of_mem;
+					}
+				}
+			}
+			if (expr_l) {
+				expr_l->next = new_expr;
+			} else {
+				new_con->expr = new_expr;
+			}
+			expr_l = new_expr;
+			new_expr = NULL;
+		}
+		if (last_new_con == NULL) {
+			*dst = new_con;
+		} else {
+			last_new_con->next = new_con;
+		}
+		last_new_con = new_con;
+		src = src->next;
+	}
+
+	return 0;
+      out_of_mem:
+	ERR(state->handle, "Out of memory!");
+	if (new_con)
+		free(new_con);
+	constraint_expr_destroy(new_expr);
+	return -1;
+}
+
+static int class_copy_default_new_object(expand_state_t *state,
+					 class_datum_t *olddatum,
+					 class_datum_t *newdatum)
+{
+	if (olddatum->default_user) {
+		if (newdatum->default_user && olddatum->default_user != newdatum->default_user) {
+			ERR(state->handle, "Found conflicting default user definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_user = olddatum->default_user;
+
+	}
+	if (olddatum->default_role) {
+		if (newdatum->default_role && olddatum->default_role != newdatum->default_role) {
+			ERR(state->handle, "Found conflicting default role definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_role = olddatum->default_role;
+	}
+	if (olddatum->default_type) {
+		if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
+			ERR(state->handle, "Found conflicting default type definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_type = olddatum->default_type;
+	}
+	if (olddatum->default_range) {
+		if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
+			ERR(state->handle, "Found conflicting default range definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_range = olddatum->default_range;
+	}
+	return 0;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			       void *data)
+{
+	int ret;
+	char *id, *new_id;
+	class_datum_t *class, *new_class;
+	expand_state_t *state;
+
+	id = (char *)key;
+	class = (class_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (!is_id_enabled(id, state->base, SYM_CLASSES)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying class %s", id);
+
+	new_class = (class_datum_t *) malloc(sizeof(class_datum_t));
+	if (!new_class) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	memset(new_class, 0, sizeof(class_datum_t));
+	if (symtab_init(&new_class->permissions, PERM_SYMTAB_SIZE)) {
+		ERR(state->handle, "Out of memory!");
+		free(new_class);
+		return -1;
+	}
+
+	new_class->s.value = class->s.value;
+	state->out->p_classes.nprim++;
+
+	ret = class_copy_default_new_object(state, class, new_class);
+	if (ret) {
+		free(new_class);
+		return ret;
+	}
+	
+	new_id = strdup(id);
+	if (!new_id) {
+		ERR(state->handle, "Out of memory!");
+		free(new_class);
+		return -1;
+	}
+
+	ret =
+	    hashtab_insert(state->out->p_classes.table, new_id,
+			   (hashtab_datum_t *) new_class);
+	if (ret) {
+		ERR(state->handle, "hashtab overflow");
+		free(new_class);
+		free(new_id);
+		return -1;
+	}
+
+	if (hashtab_map
+	    (class->permissions.table, perm_copy_callback,
+	     &new_class->permissions)) {
+		ERR(state->handle, "hashtab overflow");
+		return -1;
+	}
+
+	if (class->comkey) {
+		new_class->comkey = strdup(class->comkey);
+		if (!new_class->comkey) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		new_class->comdatum =
+		    hashtab_search(state->out->p_commons.table,
+				   new_class->comkey);
+		if (!new_class->comdatum) {
+			ERR(state->handle, "could not find common datum %s",
+			    new_class->comkey);
+			return -1;
+		}
+		new_class->permissions.nprim +=
+		    new_class->comdatum->permissions.nprim;
+	}
+
+	return 0;
+}
+
+static int constraint_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+				    void *data)
+{
+	char *id;
+	class_datum_t *class, *new_class;
+	expand_state_t *state;
+
+	id = (char *)key;
+	class = (class_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	new_class = hashtab_search(state->out->p_classes.table, id);
+	if (!new_class) {
+		ERR(state->handle, "class %s vanished", id);
+		return -1;
+	}
+
+	/* constraints */
+	if (constraint_node_clone
+	    (&new_class->constraints, class->constraints, state) == -1
+	    || constraint_node_clone(&new_class->validatetrans,
+				     class->validatetrans, state) == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!type->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_TYPES))
+		return 0;
+
+	bounds_val = state->typemap[type->bounds - 1];
+
+	dest = hashtab_search(state->out->p_types.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	role_datum_t *role = (role_datum_t *) datum;
+	role_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!role->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_ROLES))
+		return 0;
+
+	bounds_val = state->rolemap[role->bounds - 1];
+
+	dest = hashtab_search(state->out->p_roles.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "Role lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	user_datum_t *user = (user_datum_t *) datum;
+	user_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!user->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_USERS))
+		return 0;
+
+	bounds_val = state->usermap[user->bounds - 1];
+
+	dest = hashtab_search(state->out->p_users.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "User lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be certain that
+ * the out symbol table will have the type that the alias refers. Otherwise, we
+ * won't be able to find the type value for the alias. We can't depend on the
+ * declaration ordering because of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			       void *data)
+{
+	int ret;
+	char *id, *new_id;
+	type_datum_t *alias, *new_alias;
+	expand_state_t *state;
+	uint32_t prival;
+
+	id = (char *)key;
+	alias = (type_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	/* ignore regular types */
+	if (alias->flavor == TYPE_TYPE && alias->primary)
+		return 0;
+
+	/* ignore attributes */
+	if (alias->flavor == TYPE_ATTRIB)
+		return 0;
+
+	if (alias->flavor == TYPE_ALIAS) 
+		prival = alias->primary;
+	else 
+		prival = alias->s.value;
+
+	if (!is_id_enabled(state->base->p_type_val_to_name[prival - 1],
+			state->base, SYM_TYPES)) {
+		/* The primary type for this alias is not enabled, the alias 
+ 		 * shouldn't be either */
+		return 0;
+	}
+		
+	if (state->verbose)
+		INFO(state->handle, "copying alias %s", id);
+
+	new_id = strdup(id);
+	if (!new_id) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	new_alias = (type_datum_t *) malloc(sizeof(type_datum_t));
+	if (!new_alias) {
+		ERR(state->handle, "Out of memory!");
+		free(new_id);
+		return SEPOL_ENOMEM;
+	}
+	memset(new_alias, 0, sizeof(type_datum_t));
+	if (alias->flavor == TYPE_TYPE)
+		new_alias->s.value = state->typemap[alias->s.value - 1];
+	else if (alias->flavor == TYPE_ALIAS)
+		new_alias->s.value = state->typemap[alias->primary - 1];
+	else
+		assert(0);	/* unreachable */
+
+	new_alias->flags = alias->flags;
+
+	ret = hashtab_insert(state->out->p_types.table,
+			     (hashtab_key_t) new_id,
+			     (hashtab_datum_t) new_alias);
+
+	if (ret) {
+		ERR(state->handle, "hashtab overflow");
+		free(new_alias);
+		free(new_id);
+		return -1;
+	}
+
+	state->typemap[alias->s.value - 1] = new_alias->s.value;
+
+	if (new_alias->flags & TYPE_FLAGS_PERMISSIVE)
+		if (ebitmap_set_bit(&state->out->permissive_map, new_alias->s.value, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+	return 0;
+}
+
+static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *data)
+{
+	ebitmap_t mapped_roles;
+	role_datum_t *role = (role_datum_t *) datum;
+	expand_state_t *state = (expand_state_t *) data;
+
+	if (map_ebitmap(&role->dominates, &mapped_roles, state->rolemap))
+		return -1;
+
+	ebitmap_destroy(&role->dominates);	
+	
+	if (ebitmap_cpy(&role->dominates, &mapped_roles))
+		return -1;
+
+	ebitmap_destroy(&mapped_roles);
+
+	return 0;
+}
+
+/* For the role attribute in the base module, escalate its counterpart's
+ * types.types ebitmap in the out module to the counterparts of all the
+ * regular role that belongs to the current role attribute. Note, must be
+ * invoked after role_copy_callback so that state->rolemap is available.
+ */
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	char *id, *base_reg_role_id;
+	role_datum_t *role, *new_role, *regular_role;
+	expand_state_t *state;
+	ebitmap_node_t *rnode;
+	unsigned int i;
+	ebitmap_t mapped_roles;
+
+	id = key;
+	role = (role_datum_t *)datum;
+	state = (expand_state_t *)data;
+
+	if (strcmp(id, OBJECT_R) == 0) {
+		/* object_r is never a role attribute by far */
+		return 0;
+	}
+
+	if (!is_id_enabled(id, state->base, SYM_ROLES)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (role->flavor != ROLE_ATTRIB)
+		return 0;
+
+	if (state->verbose)
+		INFO(state->handle, "fixing role attribute %s", id);
+
+	new_role =
+		(role_datum_t *)hashtab_search(state->out->p_roles.table, id);
+
+	assert(new_role != NULL && new_role->flavor == ROLE_ATTRIB);
+
+	ebitmap_init(&mapped_roles);
+	if (map_ebitmap(&role->roles, &mapped_roles, state->rolemap))
+		return -1;
+	if (ebitmap_union(&new_role->roles, &mapped_roles)) {
+		ERR(state->handle, "Out of memory!");
+		ebitmap_destroy(&mapped_roles);
+		return -1;
+	}
+	ebitmap_destroy(&mapped_roles);
+
+	ebitmap_for_each_bit(&role->roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			/* take advantage of sym_val_to_name[]
+			 * of the base module */
+			base_reg_role_id = state->base->p_role_val_to_name[i];
+			regular_role = (role_datum_t *)hashtab_search(
+						state->out->p_roles.table,
+						base_reg_role_id);
+			assert(regular_role != NULL && 
+			       regular_role->flavor == ROLE_ROLE);
+
+			if (ebitmap_union(&regular_role->types.types, 
+					  &new_role->types.types)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+	
+	return 0;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id, *new_id;
+	role_datum_t *role;
+	role_datum_t *new_role;
+	expand_state_t *state;
+	ebitmap_t tmp_union_types;
+
+	id = key;
+	role = (role_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (strcmp(id, OBJECT_R) == 0) {
+		/* object_r is always value 1 */
+		state->rolemap[role->s.value - 1] = 1;
+		return 0;
+	}
+
+	if (!is_id_enabled(id, state->base, SYM_ROLES)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying role %s", id);
+
+	new_role =
+	    (role_datum_t *) hashtab_search(state->out->p_roles.table, id);
+	if (!new_role) {
+		new_role = (role_datum_t *) malloc(sizeof(role_datum_t));
+		if (!new_role) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		memset(new_role, 0, sizeof(role_datum_t));
+
+		new_id = strdup(id);
+		if (!new_id) {
+			ERR(state->handle, "Out of memory!");
+			free(new_role);
+			return -1;
+		}
+
+		state->out->p_roles.nprim++;
+		new_role->flavor = role->flavor;
+		new_role->s.value = state->out->p_roles.nprim;
+		state->rolemap[role->s.value - 1] = new_role->s.value;
+		ret = hashtab_insert(state->out->p_roles.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_role);
+
+		if (ret) {
+			ERR(state->handle, "hashtab overflow");
+			free(new_role);
+			free(new_id);
+			return -1;
+		}
+	}
+
+	/* The dominates bitmap is going to be wrong for the moment, 
+ 	 * we'll come back later and remap them, after we are sure all 
+ 	 * the roles have been added */
+	if (ebitmap_union(&new_role->dominates, &role->dominates)) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	ebitmap_init(&tmp_union_types);
+
+	/* convert types in the role datum in the global symtab */
+	if (expand_convert_type_set
+	    (state->out, state->typemap, &role->types, &tmp_union_types, 1)) {
+		ebitmap_destroy(&tmp_union_types);
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	if (ebitmap_union(&new_role->types.types, &tmp_union_types)) {
+		ERR(state->handle, "Out of memory!");
+		ebitmap_destroy(&tmp_union_types);
+		return -1;
+	}
+	ebitmap_destroy(&tmp_union_types);
+
+	return 0;
+}
+
+int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l,
+			      policydb_t * p, sepol_handle_t * h)
+{
+	mls_semantic_cat_t *cat;
+	level_datum_t *levdatum;
+	unsigned int i;
+
+	mls_level_init(l);
+
+	if (!p->mls)
+		return 0;
+
+	/* Required not declared. */
+	if (!sl->sens)
+		return 0;
+
+	l->sens = sl->sens;
+	levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+						    p->p_sens_val_to_name[l->sens - 1]);
+	if (!levdatum) {
+		ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n",
+		    __func__);
+		errno = ENOENT;
+		return -1;
+	}
+	for (cat = sl->cat; cat; cat = cat->next) {
+		if (cat->low > cat->high) {
+			ERR(h, "Category range is not valid %s.%s",
+			    p->p_cat_val_to_name[cat->low - 1],
+			    p->p_cat_val_to_name[cat->high - 1]);
+			return -1;
+		}
+		for (i = cat->low - 1; i < cat->high; i++) {
+			if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+				ERR(h, "Category %s can not be associated with "
+				    "level %s",
+				    p->p_cat_val_to_name[i],
+				    p->p_sens_val_to_name[l->sens - 1]);
+				return -1;
+			}
+			if (ebitmap_set_bit(&l->cat, i, 1)) {
+				ERR(h, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int mls_semantic_range_expand(mls_semantic_range_t * sr, mls_range_t * r,
+			      policydb_t * p, sepol_handle_t * h)
+{
+	if (mls_semantic_level_expand(&sr->level[0], &r->level[0], p, h) < 0)
+		return -1;
+
+	if (mls_semantic_level_expand(&sr->level[1], &r->level[1], p, h) < 0) {
+		mls_semantic_level_destroy(&sr->level[0]);
+		return -1;
+	}
+
+	if (!mls_level_dom(&r->level[1], &r->level[0])) {
+		mls_range_destroy(r);
+		ERR(h, "MLS range high level does not dominate low level");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	expand_state_t *state;
+	user_datum_t *user;
+	user_datum_t *new_user;
+	char *id, *new_id;
+	ebitmap_t tmp_union;
+
+	id = key;
+	user = (user_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (!is_id_enabled(id, state->base, SYM_USERS)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying user %s", id);
+
+	new_user =
+	    (user_datum_t *) hashtab_search(state->out->p_users.table, id);
+	if (!new_user) {
+		new_user = (user_datum_t *) malloc(sizeof(user_datum_t));
+		if (!new_user) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		memset(new_user, 0, sizeof(user_datum_t));
+
+		state->out->p_users.nprim++;
+		new_user->s.value = state->out->p_users.nprim;
+		state->usermap[user->s.value - 1] = new_user->s.value;
+
+		new_id = strdup(id);
+		if (!new_id) {
+			ERR(state->handle, "Out of memory!");
+			free(new_user);
+			return -1;
+		}
+		ret = hashtab_insert(state->out->p_users.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_user);
+		if (ret) {
+			ERR(state->handle, "hashtab overflow");
+			user_datum_destroy(new_user);
+			free(new_user);
+			free(new_id);
+			return -1;
+		}
+
+		/* expand the semantic MLS info */
+		if (mls_semantic_range_expand(&user->range,
+					      &new_user->exp_range,
+					      state->out, state->handle)) {
+			return -1;
+		}
+		if (mls_semantic_level_expand(&user->dfltlevel,
+					      &new_user->exp_dfltlevel,
+					      state->out, state->handle)) {
+			return -1;
+		}
+		if (!mls_level_between(&new_user->exp_dfltlevel,
+				       &new_user->exp_range.level[0],
+				       &new_user->exp_range.level[1])) {
+			ERR(state->handle, "default level not within user "
+			    "range");
+			return -1;
+		}
+	} else {
+		/* require that the MLS info match */
+		mls_range_t tmp_range;
+		mls_level_t tmp_level;
+
+		if (mls_semantic_range_expand(&user->range, &tmp_range,
+					      state->out, state->handle)) {
+			return -1;
+		}
+		if (mls_semantic_level_expand(&user->dfltlevel, &tmp_level,
+					      state->out, state->handle)) {
+			mls_range_destroy(&tmp_range);
+			return -1;
+		}
+		if (!mls_range_eq(&new_user->exp_range, &tmp_range) ||
+		    !mls_level_eq(&new_user->exp_dfltlevel, &tmp_level)) {
+			mls_range_destroy(&tmp_range);
+			mls_level_destroy(&tmp_level);
+			return -1;
+		}
+		mls_range_destroy(&tmp_range);
+		mls_level_destroy(&tmp_level);
+	}
+
+	ebitmap_init(&tmp_union);
+
+	/* get global roles for this user */
+	if (role_set_expand(&user->roles, &tmp_union, state->out, state->base, state->rolemap)) {
+		ERR(state->handle, "Out of memory!");
+		ebitmap_destroy(&tmp_union);
+		return -1;
+	}
+
+	if (ebitmap_union(&new_user->roles.roles, &tmp_union)) {
+		ERR(state->handle, "Out of memory!");
+		ebitmap_destroy(&tmp_union);
+		return -1;
+	}
+	ebitmap_destroy(&tmp_union);
+
+	return 0;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	expand_state_t *state;
+	cond_bool_datum_t *bool, *new_bool;
+	char *id, *new_id;
+
+	id = key;
+	bool = (cond_bool_datum_t *) datum;
+	state = (expand_state_t *) data;
+
+	if (!is_id_enabled(id, state->base, SYM_BOOLS)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (bool->flags & COND_BOOL_FLAGS_TUNABLE) {
+		/* Skip tunables */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying boolean %s", id);
+
+	new_bool = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t));
+	if (!new_bool) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	new_id = strdup(id);
+	if (!new_id) {
+		ERR(state->handle, "Out of memory!");
+		free(new_bool);
+		return -1;
+	}
+
+	state->out->p_bools.nprim++;
+	new_bool->s.value = state->out->p_bools.nprim;
+
+	ret = hashtab_insert(state->out->p_bools.table,
+			     (hashtab_key_t) new_id,
+			     (hashtab_datum_t) new_bool);
+	if (ret) {
+		ERR(state->handle, "hashtab overflow");
+		free(new_bool);
+		free(new_id);
+		return -1;
+	}
+
+	state->boolmap[bool->s.value - 1] = new_bool->s.value;
+
+	new_bool->state = bool->state;
+	new_bool->flags = bool->flags;
+
+	return 0;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	level_datum_t *level = (level_datum_t *) datum, *new_level = NULL;
+	char *id = (char *)key, *new_id = NULL;
+
+	if (!is_id_enabled(id, state->base, SYM_LEVELS)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying sensitivity level %s", id);
+
+	new_level = (level_datum_t *) malloc(sizeof(level_datum_t));
+	if (!new_level)
+		goto out_of_mem;
+	level_datum_init(new_level);
+	new_level->level = (mls_level_t *) malloc(sizeof(mls_level_t));
+	if (!new_level->level)
+		goto out_of_mem;
+	mls_level_init(new_level->level);
+	new_id = strdup(id);
+	if (!new_id)
+		goto out_of_mem;
+
+	if (mls_level_cpy(new_level->level, level->level)) {
+		goto out_of_mem;
+	}
+	new_level->isalias = level->isalias;
+	state->out->p_levels.nprim++;
+
+	if (hashtab_insert(state->out->p_levels.table,
+			   (hashtab_key_t) new_id,
+			   (hashtab_datum_t) new_level)) {
+		goto out_of_mem;
+	}
+	return 0;
+
+      out_of_mem:
+	ERR(state->handle, "Out of memory!");
+	if (new_level != NULL && new_level->level != NULL) {
+		mls_level_destroy(new_level->level);
+		free(new_level->level);
+	}
+	level_datum_destroy(new_level);
+	free(new_level);
+	free(new_id);
+	return -1;
+}
+
+static int cats_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	cat_datum_t *cat = (cat_datum_t *) datum, *new_cat = NULL;
+	char *id = (char *)key, *new_id = NULL;
+
+	if (!is_id_enabled(id, state->base, SYM_CATS)) {
+		/* identifier's scope is not enabled */
+		return 0;
+	}
+
+	if (state->verbose)
+		INFO(state->handle, "copying category attribute %s", id);
+
+	new_cat = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+	if (!new_cat)
+		goto out_of_mem;
+	cat_datum_init(new_cat);
+	new_id = strdup(id);
+	if (!new_id)
+		goto out_of_mem;
+
+	new_cat->s.value = cat->s.value;
+	new_cat->isalias = cat->isalias;
+	state->out->p_cats.nprim++;
+	if (hashtab_insert(state->out->p_cats.table,
+			   (hashtab_key_t) new_id, (hashtab_datum_t) new_cat)) {
+		goto out_of_mem;
+	}
+
+	return 0;
+
+      out_of_mem:
+	ERR(state->handle, "Out of memory!");
+	cat_datum_destroy(new_cat);
+	free(new_cat);
+	free(new_id);
+	return -1;
+}
+
+static int copy_role_allows(expand_state_t * state, role_allow_rule_t * rules)
+{
+	unsigned int i, j;
+	role_allow_t *cur_allow, *n, *l;
+	role_allow_rule_t *cur;
+	ebitmap_t roles, new_roles;
+	ebitmap_node_t *snode, *tnode;
+
+	/* start at the end of the list */
+	for (l = state->out->role_allow; l && l->next; l = l->next) ;
+
+	cur = rules;
+	while (cur) {
+		ebitmap_init(&roles);
+		ebitmap_init(&new_roles);
+
+		if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->base, state->rolemap)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		ebitmap_for_each_bit(&roles, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			ebitmap_for_each_bit(&new_roles, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+				/* check for duplicates */
+				cur_allow = state->out->role_allow;
+				while (cur_allow) {
+					if ((cur_allow->role == i + 1) &&
+					    (cur_allow->new_role == j + 1))
+						break;
+					cur_allow = cur_allow->next;
+				}
+				if (cur_allow)
+					continue;
+				n = (role_allow_t *)
+				    malloc(sizeof(role_allow_t));
+				if (!n) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				memset(n, 0, sizeof(role_allow_t));
+				n->role = i + 1;
+				n->new_role = j + 1;
+				if (l) {
+					l->next = n;
+				} else {
+					state->out->role_allow = n;
+				}
+				l = n;
+			}
+		}
+
+		ebitmap_destroy(&roles);
+		ebitmap_destroy(&new_roles);
+
+		cur = cur->next;
+	}
+
+	return 0;
+}
+
+static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
+{
+	unsigned int i, j, k;
+	role_trans_t *n, *l, *cur_trans;
+	role_trans_rule_t *cur;
+	ebitmap_t roles, types;
+	ebitmap_node_t *rnode, *tnode, *cnode;
+
+	/* start at the end of the list */
+	for (l = state->out->role_tr; l && l->next; l = l->next) ;
+
+	cur = rules;
+	while (cur) {
+		ebitmap_init(&roles);
+		ebitmap_init(&types);
+
+		if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		if (expand_convert_type_set
+		    (state->out, state->typemap, &cur->types, &types, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		ebitmap_for_each_bit(&roles, rnode, i) {
+			if (!ebitmap_node_get_bit(rnode, i))
+				continue;
+			ebitmap_for_each_bit(&types, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+				ebitmap_for_each_bit(&cur->classes, cnode, k) {
+					if (!ebitmap_node_get_bit(cnode, k))
+						continue;
+
+					cur_trans = state->out->role_tr;
+					while (cur_trans) {
+						unsigned int mapped_role;
+
+						mapped_role = state->rolemap[cur->new_role - 1];
+
+						if ((cur_trans->role ==
+								i + 1) &&
+						    (cur_trans->type ==
+								j + 1) &&
+						    (cur_trans->tclass ==
+								k + 1)) {
+							if (cur_trans->new_role == mapped_role) {
+								break;
+							} else {
+								ERR(state->handle,
+									"Conflicting role trans rule %s %s : %s { %s vs %s }",
+									state->out->p_role_val_to_name[i],
+									state->out->p_type_val_to_name[j],
+									state->out->p_class_val_to_name[k],
+									state->out->p_role_val_to_name[mapped_role - 1],
+									state->out->p_role_val_to_name[cur_trans->new_role - 1]);
+								return -1;
+							}
+						}
+						cur_trans = cur_trans->next;
+					}
+					if (cur_trans)
+						continue;
+
+					n = (role_trans_t *)
+						malloc(sizeof(role_trans_t));
+					if (!n) {
+						ERR(state->handle,
+							"Out of memory!");
+						return -1;
+					}
+					memset(n, 0, sizeof(role_trans_t));
+					n->role = i + 1;
+					n->type = j + 1;
+					n->tclass = k + 1;
+					n->new_role = state->rolemap
+							[cur->new_role - 1];
+					if (l)
+						l->next = n;
+					else
+						state->out->role_tr = n;
+
+					l = n;
+				}
+			}
+		}
+
+		ebitmap_destroy(&roles);
+		ebitmap_destroy(&types);
+
+		cur = cur->next;
+	}
+	return 0;
+}
+
+static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules)
+{
+	unsigned int i, j;
+	filename_trans_t *new_trans, *cur_trans;
+	filename_trans_rule_t *cur_rule;
+	ebitmap_t stypes, ttypes;
+	ebitmap_node_t *snode, *tnode;
+
+	cur_rule = rules;
+	while (cur_rule) {
+		uint32_t mapped_otype;
+
+		ebitmap_init(&stypes);
+		ebitmap_init(&ttypes);
+
+		if (expand_convert_type_set(state->out, state->typemap,
+					    &cur_rule->stypes, &stypes, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		if (expand_convert_type_set(state->out, state->typemap,
+					    &cur_rule->ttypes, &ttypes, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		mapped_otype = state->typemap[cur_rule->otype - 1];
+
+		ebitmap_for_each_bit(&stypes, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			ebitmap_for_each_bit(&ttypes, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+
+				cur_trans = state->out->filename_trans;
+				while (cur_trans) {
+					if ((cur_trans->stype == i + 1) &&
+					    (cur_trans->ttype == j + 1) &&
+					    (cur_trans->tclass == cur_rule->tclass) &&
+					    (!strcmp(cur_trans->name, cur_rule->name))) {
+						/* duplicate rule, who cares */
+						if (cur_trans->otype == mapped_otype)
+							break;
+
+						ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\":  %s vs %s",
+						    state->out->p_type_val_to_name[i],
+						    state->out->p_type_val_to_name[j],
+						    state->out->p_class_val_to_name[cur_trans->tclass - 1],
+						    cur_trans->name,
+						    state->out->p_type_val_to_name[cur_trans->otype - 1],
+						    state->out->p_type_val_to_name[mapped_otype - 1]);
+
+						return -1;
+					}
+					cur_trans = cur_trans->next;
+				}
+				/* duplicate rule, who cares */
+				if (cur_trans)
+					continue;
+
+				new_trans = malloc(sizeof(*new_trans));
+				if (!new_trans) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				memset(new_trans, 0, sizeof(*new_trans));
+				new_trans->next = state->out->filename_trans;
+				state->out->filename_trans = new_trans;
+
+				new_trans->name = strdup(cur_rule->name);
+				if (!new_trans->name) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				new_trans->stype = i + 1;
+				new_trans->ttype = j + 1;
+				new_trans->tclass = cur_rule->tclass;
+				new_trans->otype = mapped_otype;
+			}
+		}
+
+		ebitmap_destroy(&stypes);
+		ebitmap_destroy(&ttypes);
+
+		cur_rule = cur_rule->next;
+	}
+	return 0;
+}
+
+static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass,
+			      mls_semantic_range_t * trange,
+			      expand_state_t * state)
+{
+	range_trans_t *rt, *check_rt = state->out->range_tr;
+	mls_range_t exp_range;
+	int rc = -1;
+
+	if (mls_semantic_range_expand(trange, &exp_range, state->out,
+				      state->handle))
+		goto out;
+
+	/* check for duplicates/conflicts */
+	while (check_rt) {
+		if ((check_rt->source_type == stype) &&
+		    (check_rt->target_type == ttype) &&
+		    (check_rt->target_class == tclass)) {
+			if (mls_range_eq(&check_rt->target_range, &exp_range)) {
+				/* duplicate */
+				break;
+			} else {
+				/* conflict */
+				ERR(state->handle,
+				    "Conflicting range trans rule %s %s : %s",
+				    state->out->p_type_val_to_name[stype - 1],
+				    state->out->p_type_val_to_name[ttype - 1],
+				    state->out->p_class_val_to_name[tclass -
+								    1]);
+				goto out;
+			}
+		}
+		check_rt = check_rt->next;
+	}
+	if (check_rt) {
+		/* this is a dup - skip */
+		rc = 0;
+		goto out;
+	}
+
+	rt = (range_trans_t *) calloc(1, sizeof(range_trans_t));
+	if (!rt) {
+		ERR(state->handle, "Out of memory!");
+		goto out;
+	}
+
+	rt->next = state->out->range_tr;
+	state->out->range_tr = rt;
+
+	rt->source_type = stype;
+	rt->target_type = ttype;
+	rt->target_class = tclass;
+	if (mls_range_cpy(&rt->target_range, &exp_range)) {
+		ERR(state->handle, "Out of memory!");
+		goto out;
+	}
+
+	rc = 0;
+
+      out:
+	mls_range_destroy(&exp_range);
+	return rc;
+}
+
+static int expand_range_trans(expand_state_t * state,
+			      range_trans_rule_t * rules)
+{
+	unsigned int i, j, k;
+	range_trans_rule_t *rule;
+
+	ebitmap_t stypes, ttypes;
+	ebitmap_node_t *snode, *tnode, *cnode;
+
+	if (state->verbose)
+		INFO(state->handle, "expanding range transitions");
+
+	for (rule = rules; rule; rule = rule->next) {
+		ebitmap_init(&stypes);
+		ebitmap_init(&ttypes);
+
+		/* expand the type sets */
+		if (expand_convert_type_set(state->out, state->typemap,
+					    &rule->stypes, &stypes, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		if (expand_convert_type_set(state->out, state->typemap,
+					    &rule->ttypes, &ttypes, 1)) {
+			ebitmap_destroy(&stypes);
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		/* loop on source type */
+		ebitmap_for_each_bit(&stypes, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			/* loop on target type */
+			ebitmap_for_each_bit(&ttypes, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+				/* loop on target class */
+				ebitmap_for_each_bit(&rule->tclasses, cnode, k) {
+					if (!ebitmap_node_get_bit(cnode, k))
+						continue;
+
+					if (exp_rangetr_helper(i + 1,
+							       j + 1,
+							       k + 1,
+							       &rule->trange,
+							       state)) {
+						ebitmap_destroy(&stypes);
+						ebitmap_destroy(&ttypes);
+						return -1;
+					}
+				}
+			}
+		}
+
+		ebitmap_destroy(&stypes);
+		ebitmap_destroy(&ttypes);
+	}
+
+	return 0;
+}
+
+/* Search for an AV tab node within a hash table with the given key.
+ * If the node does not exist, create it and return it; otherwise
+ * return the pre-existing one.
+*/
+static avtab_ptr_t find_avtab_node(sepol_handle_t * handle,
+				   avtab_t * avtab, avtab_key_t * key,
+				   cond_av_list_t ** cond,
+				   av_extended_perms_t *xperms)
+{
+	avtab_ptr_t node;
+	avtab_datum_t avdatum;
+	cond_av_list_t *nl;
+	int match = 0;
+
+	/* AVTAB_XPERMS entries are not necessarily unique */
+	if (key->specified & AVTAB_XPERMS) {
+		node = avtab_search_node(avtab, key);
+		while (node) {
+			if ((node->datum.xperms->specified == xperms->specified) &&
+				(node->datum.xperms->driver == xperms->driver)) {
+				match = 1;
+				break;
+			}
+			node = avtab_search_node_next(node, key->specified);
+		}
+		if (!match)
+			node = NULL;
+	} else {
+		node = avtab_search_node(avtab, key);
+	}
+
+	/* If this is for conditional policies, keep searching in case
+	   the node is part of my conditional avtab. */
+	if (cond) {
+		while (node) {
+			if (node->parse_context == cond)
+				break;
+			node = avtab_search_node_next(node, key->specified);
+		}
+	}
+
+	if (!node) {
+		memset(&avdatum, 0, sizeof avdatum);
+		/* this is used to get the node - insertion is actually unique */
+		node = avtab_insert_nonunique(avtab, key, &avdatum);
+		if (!node) {
+			ERR(handle, "hash table overflow");
+			return NULL;
+		}
+		if (cond) {
+			node->parse_context = cond;
+			nl = (cond_av_list_t *) malloc(sizeof(cond_av_list_t));
+			if (!nl) {
+				ERR(handle, "Memory error");
+				return NULL;
+			}
+			memset(nl, 0, sizeof(cond_av_list_t));
+			nl->node = node;
+			nl->next = *cond;
+			*cond = nl;
+		}
+	}
+
+	return node;
+}
+
+#define EXPAND_RULE_SUCCESS   1
+#define EXPAND_RULE_CONFLICT  0
+#define EXPAND_RULE_ERROR    -1
+
+static int expand_terule_helper(sepol_handle_t * handle,
+				policydb_t * p, uint32_t * typemap,
+				uint32_t specified, cond_av_list_t ** cond,
+				cond_av_list_t ** other, uint32_t stype,
+				uint32_t ttype, class_perm_node_t * perms,
+				avtab_t * avtab, int enabled)
+{
+	avtab_key_t avkey;
+	avtab_datum_t *avdatump;
+	avtab_ptr_t node;
+	class_perm_node_t *cur;
+	int conflict;
+	uint32_t oldtype = 0, spec = 0;
+
+	if (specified & AVRULE_TRANSITION) {
+		spec = AVTAB_TRANSITION;
+	} else if (specified & AVRULE_MEMBER) {
+		spec = AVTAB_MEMBER;
+	} else if (specified & AVRULE_CHANGE) {
+		spec = AVTAB_CHANGE;
+	} else {
+		assert(0);	/* unreachable */
+	}
+
+	cur = perms;
+	while (cur) {
+		uint32_t remapped_data =
+		    typemap ? typemap[cur->data - 1] : cur->data;
+		avkey.source_type = stype + 1;
+		avkey.target_type = ttype + 1;
+		avkey.target_class = cur->tclass;
+		avkey.specified = spec;
+
+		conflict = 0;
+		/* check to see if the expanded TE already exists --
+		 * either in the global scope or in another
+		 * conditional AV tab */
+		node = avtab_search_node(&p->te_avtab, &avkey);
+		if (node) {
+			conflict = 1;
+		} else {
+			node = avtab_search_node(&p->te_cond_avtab, &avkey);
+			if (node && node->parse_context != other) {
+				conflict = 2;
+			}
+		}
+
+		if (conflict) {
+			avdatump = &node->datum;
+			if (specified & AVRULE_TRANSITION) {
+				oldtype = avdatump->data;
+			} else if (specified & AVRULE_MEMBER) {
+				oldtype = avdatump->data;
+			} else if (specified & AVRULE_CHANGE) {
+				oldtype = avdatump->data;
+			}
+
+			if (oldtype == remapped_data) {
+				/* if the duplicate is inside the same scope (eg., unconditional 
+				 * or in same conditional then ignore it */
+				if ((conflict == 1 && cond == NULL)
+				    || node->parse_context == cond)
+					return EXPAND_RULE_SUCCESS;
+				ERR(handle, "duplicate TE rule for %s %s:%s %s",
+				    p->p_type_val_to_name[avkey.source_type -
+							  1],
+				    p->p_type_val_to_name[avkey.target_type -
+							  1],
+				    p->p_class_val_to_name[avkey.target_class -
+							   1],
+				    p->p_type_val_to_name[oldtype - 1]);
+				return EXPAND_RULE_CONFLICT;
+			}
+			ERR(handle,
+			    "conflicting TE rule for (%s, %s:%s):  old was %s, new is %s",
+			    p->p_type_val_to_name[avkey.source_type - 1],
+			    p->p_type_val_to_name[avkey.target_type - 1],
+			    p->p_class_val_to_name[avkey.target_class - 1],
+			    p->p_type_val_to_name[oldtype - 1],
+			    p->p_type_val_to_name[remapped_data - 1]);
+			return EXPAND_RULE_CONFLICT;
+		}
+
+		node = find_avtab_node(handle, avtab, &avkey, cond, NULL);
+		if (!node)
+			return -1;
+		if (enabled) {
+			node->key.specified |= AVTAB_ENABLED;
+		} else {
+			node->key.specified &= ~AVTAB_ENABLED;
+		}
+
+		avdatump = &node->datum;
+		if (specified & AVRULE_TRANSITION) {
+			avdatump->data = remapped_data;
+		} else if (specified & AVRULE_MEMBER) {
+			avdatump->data = remapped_data;
+		} else if (specified & AVRULE_CHANGE) {
+			avdatump->data = remapped_data;
+		} else {
+			assert(0);	/* should never occur */
+		}
+
+		cur = cur->next;
+	}
+
+	return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_avrule_helper(sepol_handle_t * handle,
+				uint32_t specified,
+				cond_av_list_t ** cond,
+				uint32_t stype, uint32_t ttype,
+				class_perm_node_t * perms, avtab_t * avtab,
+				int enabled, av_extended_perms_t *extended_perms)
+{
+	avtab_key_t avkey;
+	avtab_datum_t *avdatump;
+	avtab_extended_perms_t *xperms;
+	avtab_ptr_t node;
+	class_perm_node_t *cur;
+	uint32_t spec = 0;
+	unsigned int i;
+
+	if (specified & AVRULE_ALLOWED) {
+		spec = AVTAB_ALLOWED;
+	} else if (specified & AVRULE_AUDITALLOW) {
+		spec = AVTAB_AUDITALLOW;
+	} else if (specified & AVRULE_AUDITDENY) {
+		spec = AVTAB_AUDITDENY;
+	} else if (specified & AVRULE_DONTAUDIT) {
+		if (handle && handle->disable_dontaudit)
+			return EXPAND_RULE_SUCCESS;
+		spec = AVTAB_AUDITDENY;
+	} else if (specified & AVRULE_NEVERALLOW) {
+		spec = AVTAB_NEVERALLOW;
+	} else if (specified & AVRULE_XPERMS_ALLOWED) {
+		spec = AVTAB_XPERMS_ALLOWED;
+	} else if (specified & AVRULE_XPERMS_AUDITALLOW) {
+		spec = AVTAB_XPERMS_AUDITALLOW;
+	} else if (specified & AVRULE_XPERMS_DONTAUDIT) {
+		if (handle && handle->disable_dontaudit)
+			return EXPAND_RULE_SUCCESS;
+		spec = AVTAB_XPERMS_DONTAUDIT;
+	} else if (specified & AVRULE_XPERMS_NEVERALLOW) {
+		spec = AVTAB_XPERMS_NEVERALLOW;
+	} else {
+		assert(0);	/* unreachable */
+	}
+
+	cur = perms;
+	while (cur) {
+		avkey.source_type = stype + 1;
+		avkey.target_type = ttype + 1;
+		avkey.target_class = cur->tclass;
+		avkey.specified = spec;
+
+		node = find_avtab_node(handle, avtab, &avkey, cond, extended_perms);
+		if (!node)
+			return EXPAND_RULE_ERROR;
+		if (enabled) {
+			node->key.specified |= AVTAB_ENABLED;
+		} else {
+			node->key.specified &= ~AVTAB_ENABLED;
+		}
+
+		avdatump = &node->datum;
+		if (specified & AVRULE_ALLOWED) {
+			avdatump->data |= cur->data;
+		} else if (specified & AVRULE_AUDITALLOW) {
+			avdatump->data |= cur->data;
+		} else if (specified & AVRULE_NEVERALLOW) {
+			avdatump->data |= cur->data;
+		} else if (specified & AVRULE_AUDITDENY) {
+			/* Since a '0' in an auditdeny mask represents
+			 * a permission we do NOT want to audit
+			 * (dontaudit), we use the '&' operand to
+			 * ensure that all '0's in the mask are
+			 * retained (much unlike the allow and
+			 * auditallow cases).
+			 */
+			avdatump->data &= cur->data;
+		} else if (specified & AVRULE_DONTAUDIT) {
+			if (avdatump->data)
+				avdatump->data &= ~cur->data;
+			else
+				avdatump->data = ~cur->data;
+		} else if (specified & AVRULE_XPERMS) {
+			if (!avdatump->xperms) {
+				xperms = (avtab_extended_perms_t *)
+					calloc(1, sizeof(avtab_extended_perms_t));
+				if (!xperms) {
+					ERR(handle, "Out of memory!");
+					return -1;
+				}
+				node->datum.xperms = xperms;
+			}
+			node->datum.xperms->specified = extended_perms->specified;
+			node->datum.xperms->driver = extended_perms->driver;
+
+			for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+				node->datum.xperms->perms[i] |= extended_perms->perms[i];
+		} else {
+			assert(0);	/* should never occur */
+		}
+
+		cur = cur->next;
+	}
+	return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_rule_helper(sepol_handle_t * handle,
+			      policydb_t * p, uint32_t * typemap,
+			      avrule_t * source_rule, avtab_t * dest_avtab,
+			      cond_av_list_t ** cond, cond_av_list_t ** other,
+			      int enabled,
+			      ebitmap_t * stypes, ebitmap_t * ttypes)
+{
+	unsigned int i, j;
+	int retval;
+	ebitmap_node_t *snode, *tnode;
+
+	ebitmap_for_each_bit(stypes, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		if (source_rule->flags & RULE_SELF) {
+			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
+				retval = expand_avrule_helper(handle, source_rule->specified,
+							      cond, i, i, source_rule->perms,
+							      dest_avtab, enabled, source_rule->xperms);
+				if (retval != EXPAND_RULE_SUCCESS)
+					return retval;
+			} else {
+				retval = expand_terule_helper(handle, p, typemap,
+							      source_rule->specified, cond,
+							      other, i, i, source_rule->perms,
+							      dest_avtab, enabled);
+				if (retval != EXPAND_RULE_SUCCESS)
+					return retval;
+			}
+		}
+		ebitmap_for_each_bit(ttypes, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
+				retval = expand_avrule_helper(handle, source_rule->specified,
+							      cond, i, j, source_rule->perms,
+							      dest_avtab, enabled, source_rule->xperms);
+				if (retval != EXPAND_RULE_SUCCESS)
+					return retval;
+			} else {
+				retval = expand_terule_helper(handle, p, typemap,
+							      source_rule->specified, cond,
+							      other, i, j, source_rule->perms,
+							      dest_avtab, enabled);
+				if (retval != EXPAND_RULE_SUCCESS)
+					return retval;
+			}
+		}
+	}
+
+	return EXPAND_RULE_SUCCESS;
+}
+
+/*
+ * Expand a rule into a given avtab - checking for conflicting type
+ * rules in the destination policy.  Return EXPAND_RULE_SUCCESS on 
+ * success, EXPAND_RULE_CONFLICT if the rule conflicts with something
+ * (and hence was not added), or EXPAND_RULE_ERROR on error.
+ */
+static int convert_and_expand_rule(sepol_handle_t * handle,
+				   policydb_t * dest_pol, uint32_t * typemap,
+				   avrule_t * source_rule, avtab_t * dest_avtab,
+				   cond_av_list_t ** cond,
+				   cond_av_list_t ** other, int enabled,
+				   int do_neverallow)
+{
+	int retval;
+	ebitmap_t stypes, ttypes;
+	unsigned char alwaysexpand;
+
+	if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW)
+		return EXPAND_RULE_SUCCESS;
+	if (!do_neverallow && source_rule->specified & AVRULE_XPERMS_NEVERALLOW)
+		return EXPAND_RULE_SUCCESS;
+
+	ebitmap_init(&stypes);
+	ebitmap_init(&ttypes);
+
+	/* Force expansion for type rules and for self rules. */
+	alwaysexpand = ((source_rule->specified & AVRULE_TYPE) ||
+			(source_rule->flags & RULE_SELF));
+
+	if (expand_convert_type_set
+	    (dest_pol, typemap, &source_rule->stypes, &stypes, alwaysexpand))
+		return EXPAND_RULE_ERROR;
+	if (expand_convert_type_set
+	    (dest_pol, typemap, &source_rule->ttypes, &ttypes, alwaysexpand))
+		return EXPAND_RULE_ERROR;
+
+	retval = expand_rule_helper(handle, dest_pol, typemap,
+				    source_rule, dest_avtab,
+				    cond, other, enabled, &stypes, &ttypes);
+	ebitmap_destroy(&stypes);
+	ebitmap_destroy(&ttypes);
+	return retval;
+}
+
+static int cond_avrule_list_copy(policydb_t * dest_pol, avrule_t * source_rules,
+				 avtab_t * dest_avtab, cond_av_list_t ** list,
+				 cond_av_list_t ** other, uint32_t * typemap,
+				 int enabled, expand_state_t * state)
+{
+	avrule_t *cur;
+
+	cur = source_rules;
+	while (cur) {
+		if (convert_and_expand_rule(state->handle, dest_pol,
+					    typemap, cur, dest_avtab,
+					    list, other, enabled,
+					    0) != EXPAND_RULE_SUCCESS) {
+			return -1;
+		}
+
+		cur = cur->next;
+	}
+
+	return 0;
+}
+
+static int cond_node_map_bools(expand_state_t * state, cond_node_t * cn)
+{
+	cond_expr_t *cur;
+	unsigned int i;
+
+	cur = cn->expr;
+	while (cur) {
+		if (cur->bool)
+			cur->bool = state->boolmap[cur->bool - 1];
+		cur = cur->next;
+	}
+
+	for (i = 0; i < min(cn->nbools, COND_MAX_BOOLS); i++)
+		cn->bool_ids[i] = state->boolmap[cn->bool_ids[i] - 1];
+
+	if (cond_normalize_expr(state->out, cn)) {
+		ERR(state->handle, "Error while normalizing conditional");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* copy the nodes in *reverse* order -- the result is that the last
+ * given conditional appears first in the policy, so as to match the
+ * behavior of the upstream compiler */
+static int cond_node_copy(expand_state_t * state, cond_node_t * cn)
+{
+	cond_node_t *new_cond, *tmp;
+
+	if (cn == NULL) {
+		return 0;
+	}
+	if (cond_node_copy(state, cn->next)) {
+		return -1;
+	}
+
+	/* If current cond_node_t is of tunable, its effective branch
+	 * has been appended to its home decl->avrules list during link
+	 * and now we should just skip it. */
+	if (cn->flags & COND_NODE_FLAGS_TUNABLE)
+		return 0;
+
+	if (cond_normalize_expr(state->base, cn)) {
+		ERR(state->handle, "Error while normalizing conditional");
+		return -1;
+	}
+
+	/* create a new temporary conditional node with the booleans
+	 * mapped */
+	tmp = cond_node_create(state->base, cn);
+	if (!tmp) {
+		ERR(state->handle, "Out of memory");
+		return -1;
+	}
+
+	if (cond_node_map_bools(state, tmp)) {
+		cond_node_destroy(tmp);
+		free(tmp);
+		ERR(state->handle, "Error mapping booleans");
+		return -1;
+	}
+
+	new_cond = cond_node_search(state->out, state->out->cond_list, tmp);
+	if (!new_cond) {
+		cond_node_destroy(tmp);
+		free(tmp);
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	cond_node_destroy(tmp);
+	free(tmp);
+
+	if (cond_avrule_list_copy
+	    (state->out, cn->avtrue_list, &state->out->te_cond_avtab,
+	     &new_cond->true_list, &new_cond->false_list, state->typemap,
+	     new_cond->cur_state, state))
+		return -1;
+	if (cond_avrule_list_copy
+	    (state->out, cn->avfalse_list, &state->out->te_cond_avtab,
+	     &new_cond->false_list, &new_cond->true_list, state->typemap,
+	     !new_cond->cur_state, state))
+		return -1;
+
+	return 0;
+}
+
+static int context_copy(context_struct_t * dst, context_struct_t * src,
+			expand_state_t * state)
+{
+	dst->user = state->usermap[src->user - 1];
+	dst->role = state->rolemap[src->role - 1];
+	dst->type = state->typemap[src->type - 1];
+	return mls_context_cpy(dst, src);
+}
+
+static int ocontext_copy_xen(expand_state_t *state)
+{
+	unsigned int i;
+	ocontext_t *c, *n, *l;
+
+	for (i = 0; i < OCON_NUM; i++) {
+		l = NULL;
+		for (c = state->base->ocontexts[i]; c; c = c->next) {
+			n = malloc(sizeof(ocontext_t));
+			if (!n) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			memset(n, 0, sizeof(ocontext_t));
+			if (l)
+				l->next = n;
+			else
+				state->out->ocontexts[i] = n;
+			l = n;
+			switch (i) {
+			case OCON_XEN_ISID:
+				if (c->context[0].user == 0) {
+					ERR(state->handle,
+					    "Missing context for %s initial sid",
+					    c->u.name);
+					return -1;
+				}
+				n->sid[0] = c->sid[0];
+				break;
+			case OCON_XEN_PIRQ:
+				n->u.pirq = c->u.pirq;
+				break;
+			case OCON_XEN_IOPORT:
+				n->u.ioport.low_ioport = c->u.ioport.low_ioport;
+				n->u.ioport.high_ioport =
+					c->u.ioport.high_ioport;
+				break;
+			case OCON_XEN_IOMEM:
+				n->u.iomem.low_iomem  = c->u.iomem.low_iomem;
+				n->u.iomem.high_iomem = c->u.iomem.high_iomem;
+				break;
+			case OCON_XEN_PCIDEVICE:
+				n->u.device = c->u.device;
+				break;
+			case OCON_XEN_DEVICETREE:
+				n->u.name = strdup(c->u.name);
+				if (!n->u.name) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				break;
+			default:
+				/* shouldn't get here */
+				ERR(state->handle, "Unknown ocontext");
+				return -1;
+			}
+			if (context_copy(&n->context[0], &c->context[0],
+				state)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ocontext_copy_selinux(expand_state_t *state)
+{
+	unsigned int i, j;
+	ocontext_t *c, *n, *l;
+
+	for (i = 0; i < OCON_NUM; i++) {
+		l = NULL;
+		for (c = state->base->ocontexts[i]; c; c = c->next) {
+			n = malloc(sizeof(ocontext_t));
+			if (!n) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			memset(n, 0, sizeof(ocontext_t));
+			if (l)
+				l->next = n;
+			else
+				state->out->ocontexts[i] = n;
+			l = n;
+			switch (i) {
+			case OCON_ISID:
+				if (c->context[0].user == 0) {
+					ERR(state->handle,
+					    "Missing context for %s initial sid",
+					    c->u.name);
+					return -1;
+				}
+				n->sid[0] = c->sid[0];
+				break;
+			case OCON_FS:	/* FALLTHROUGH */
+			case OCON_NETIF:
+				n->u.name = strdup(c->u.name);
+				if (!n->u.name) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				if (context_copy
+				    (&n->context[1], &c->context[1], state)) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				break;
+			case OCON_PORT:
+				n->u.port.protocol = c->u.port.protocol;
+				n->u.port.low_port = c->u.port.low_port;
+				n->u.port.high_port = c->u.port.high_port;
+				break;
+			case OCON_NODE:
+				n->u.node.addr = c->u.node.addr;
+				n->u.node.mask = c->u.node.mask;
+				break;
+			case OCON_FSUSE:
+				n->v.behavior = c->v.behavior;
+				n->u.name = strdup(c->u.name);
+				if (!n->u.name) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				break;
+			case OCON_NODE6:
+				for (j = 0; j < 4; j++)
+					n->u.node6.addr[j] = c->u.node6.addr[j];
+				for (j = 0; j < 4; j++)
+					n->u.node6.mask[j] = c->u.node6.mask[j];
+				break;
+			default:
+				/* shouldn't get here */
+				ERR(state->handle, "Unknown ocontext");
+				return -1;
+			}
+			if (context_copy(&n->context[0], &c->context[0], state)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ocontext_copy(expand_state_t *state, uint32_t target)
+{
+	int rc = -1;
+	switch (target) {
+	case SEPOL_TARGET_SELINUX:
+		rc = ocontext_copy_selinux(state);
+		break;
+	case SEPOL_TARGET_XEN:
+		rc = ocontext_copy_xen(state);
+		break;
+	default:
+		ERR(state->handle, "Unknown target");
+		return -1;
+	}
+	return rc;
+}
+
+static int genfs_copy(expand_state_t * state)
+{
+	ocontext_t *c, *newc, *l;
+	genfs_t *genfs, *newgenfs, *end;
+
+	end = NULL;
+	for (genfs = state->base->genfs; genfs; genfs = genfs->next) {
+		newgenfs = malloc(sizeof(genfs_t));
+		if (!newgenfs) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		memset(newgenfs, 0, sizeof(genfs_t));
+		newgenfs->fstype = strdup(genfs->fstype);
+		if (!newgenfs->fstype) {
+			free(newgenfs);
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		if (!end)
+			state->out->genfs = newgenfs;
+		else
+			end->next = newgenfs;
+		end = newgenfs;
+
+		l = NULL;
+		for (c = genfs->head; c; c = c->next) {
+			newc = malloc(sizeof(ocontext_t));
+			if (!newc) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			memset(newc, 0, sizeof(ocontext_t));
+			newc->u.name = strdup(c->u.name);
+			if (!newc->u.name) {
+				ERR(state->handle, "Out of memory!");
+				free(newc);
+				return -1;
+			}
+			newc->v.sclass = c->v.sclass;
+			context_copy(&newc->context[0], &c->context[0], state);
+			if (l)
+				l->next = newc;
+			else
+				newgenfs->head = newc;
+			l = newc;
+		}
+	}
+	return 0;
+}
+
+static int type_attr_map(hashtab_key_t key
+			 __attribute__ ((unused)), hashtab_datum_t datum,
+			 void *ptr)
+{
+	type_datum_t *type;
+	expand_state_t *state = ptr;
+	policydb_t *p = state->out;
+	unsigned int i;
+	ebitmap_node_t *tnode;
+	int value;
+
+	type = (type_datum_t *) datum;
+	value = type->s.value;
+
+	if (type->flavor == TYPE_ATTRIB) {
+		if (ebitmap_cpy(&p->attr_type_map[value - 1], &type->types)) {
+			goto oom;
+		}
+		ebitmap_for_each_bit(&type->types, tnode, i) {
+			if (!ebitmap_node_get_bit(tnode, i))
+				continue;
+			if (ebitmap_set_bit(&p->type_attr_map[i], value - 1, 1)) {
+				goto oom;
+			}
+		}
+	} else {
+		if (ebitmap_set_bit(&p->attr_type_map[value - 1], value - 1, 1)) {
+			goto oom;
+		}
+	}
+
+	return 0;
+
+oom:
+	ERR(state->handle, "Out of memory!");
+	return -1;
+}
+
+/* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy.
+ * this should not be called until after all the blocks have been processed and the attributes in target policy
+ * are complete. */
+int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+			    type_set_t * set, ebitmap_t * types,
+			    unsigned char alwaysexpand)
+{
+	type_set_t tmpset;
+
+	type_set_init(&tmpset);
+
+	if (map_ebitmap(&set->types, &tmpset.types, typemap))
+		return -1;
+
+	if (map_ebitmap(&set->negset, &tmpset.negset, typemap))
+		return -1;
+
+	tmpset.flags = set->flags;
+
+	if (type_set_expand(&tmpset, types, p, alwaysexpand))
+		return -1;
+
+	type_set_destroy(&tmpset);
+
+	return 0;
+}
+
+/* Expand a rule into a given avtab - checking for conflicting type
+ * rules.  Return 1 on success, 0 if the rule conflicts with something
+ * (and hence was not added), or -1 on error. */
+int expand_rule(sepol_handle_t * handle,
+		policydb_t * source_pol,
+		avrule_t * source_rule, avtab_t * dest_avtab,
+		cond_av_list_t ** cond, cond_av_list_t ** other, int enabled)
+{
+	int retval;
+	ebitmap_t stypes, ttypes;
+
+	if ((source_rule->specified & AVRULE_NEVERALLOW)
+		|| (source_rule->specified & AVRULE_XPERMS_NEVERALLOW))
+		return 1;
+
+	ebitmap_init(&stypes);
+	ebitmap_init(&ttypes);
+
+	if (type_set_expand(&source_rule->stypes, &stypes, source_pol, 1))
+		return -1;
+	if (type_set_expand(&source_rule->ttypes, &ttypes, source_pol, 1))
+		return -1;
+	retval = expand_rule_helper(handle, source_pol, NULL,
+				    source_rule, dest_avtab,
+				    cond, other, enabled, &stypes, &ttypes);
+	ebitmap_destroy(&stypes);
+	ebitmap_destroy(&ttypes);
+	return retval;
+}
+
+/* Expand a role set into an ebitmap containing the roles.
+ * This handles the attribute and flags.
+ * Attribute expansion depends on if the rolemap is available.
+ * During module compile the rolemap is not available, the
+ * possible duplicates of a regular role and the role attribute
+ * the regular role belongs to could be properly handled by
+ * copy_role_trans and copy_role_allow.
+ */
+int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap)
+{
+	unsigned int i;
+	ebitmap_node_t *rnode;
+	ebitmap_t mapped_roles, roles;
+	policydb_t *p = out;
+	role_datum_t *role;
+
+	ebitmap_init(r);
+
+	if (x->flags & ROLE_STAR) {
+		for (i = 0; i < p->p_roles.nprim++; i++)
+			if (ebitmap_set_bit(r, i, 1))
+				return -1;
+		return 0;
+	}
+
+	ebitmap_init(&mapped_roles);
+	ebitmap_init(&roles);
+	
+	if (rolemap) {
+		assert(base != NULL);
+		ebitmap_for_each_bit(&x->roles, rnode, i) {
+			if (ebitmap_node_get_bit(rnode, i)) {
+				/* take advantage of p_role_val_to_struct[]
+				 * of the base module */
+				role = base->role_val_to_struct[i];
+				assert(role != NULL);
+				if (role->flavor == ROLE_ATTRIB) {
+					if (ebitmap_union(&roles,
+							  &role->roles))
+						goto bad;
+				} else {
+					if (ebitmap_set_bit(&roles, i, 1))
+						goto bad;
+				}
+			}
+		}
+		if (map_ebitmap(&roles, &mapped_roles, rolemap))
+			goto bad;
+	} else {
+		if (ebitmap_cpy(&mapped_roles, &x->roles))
+			goto bad;
+	}
+
+	ebitmap_for_each_bit(&mapped_roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			if (ebitmap_set_bit(r, i, 1))
+				goto bad;
+		}
+	}
+
+	ebitmap_destroy(&mapped_roles);
+	ebitmap_destroy(&roles);
+
+	/* if role is to be complimented, invert the entire bitmap here */
+	if (x->flags & ROLE_COMP) {
+		for (i = 0; i < ebitmap_length(r); i++) {
+			if (ebitmap_get_bit(r, i)) {
+				if (ebitmap_set_bit(r, i, 0))
+					return -1;
+			} else {
+				if (ebitmap_set_bit(r, i, 1))
+					return -1;
+			}
+		}
+	}
+	return 0;
+
+bad:
+	ebitmap_destroy(&mapped_roles);
+	ebitmap_destroy(&roles);
+	return -1;
+}
+
+/* Expand a type set into an ebitmap containing the types. This
+ * handles the negset, attributes, and flags.
+ * Attribute expansion depends on several factors:
+ * - if alwaysexpand is 1, then they will be expanded,
+ * - if the type set has a negset or flags, then they will be expanded,
+ * - otherwise, they will not be expanded.
+ */
+int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+		    unsigned char alwaysexpand)
+{
+	unsigned int i;
+	ebitmap_t types, neg_types;
+	ebitmap_node_t *tnode;
+
+	ebitmap_init(&types);
+	ebitmap_init(t);
+
+	if (alwaysexpand || ebitmap_length(&set->negset) || set->flags) {
+		/* First go through the types and OR all the attributes to types */
+		ebitmap_for_each_bit(&set->types, tnode, i) {
+			if (ebitmap_node_get_bit(tnode, i)) {
+				if (p->type_val_to_struct[i]->flavor ==
+				    TYPE_ATTRIB) {
+					if (ebitmap_union
+					    (&types,
+					     &p->type_val_to_struct[i]->
+					     types)) {
+						return -1;
+					}
+				} else {
+					if (ebitmap_set_bit(&types, i, 1)) {
+						return -1;
+					}
+				}
+			}
+		}
+	} else {
+		/* No expansion of attributes, just copy the set as is. */
+		if (ebitmap_cpy(&types, &set->types))
+			return -1;
+	}
+
+	/* Now do the same thing for negset */
+	ebitmap_init(&neg_types);
+	ebitmap_for_each_bit(&set->negset, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			if (p->type_val_to_struct[i] &&
+			    p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+				if (ebitmap_union
+				    (&neg_types,
+				     &p->type_val_to_struct[i]->types)) {
+					return -1;
+				}
+			} else {
+				if (ebitmap_set_bit(&neg_types, i, 1)) {
+					return -1;
+				}
+			}
+		}
+	}
+
+	if (set->flags & TYPE_STAR) {
+		/* set all types not in neg_types */
+		for (i = 0; i < p->p_types.nprim; i++) {
+			if (ebitmap_get_bit(&neg_types, i))
+				continue;
+			if (p->type_val_to_struct[i] &&
+			    p->type_val_to_struct[i]->flavor == TYPE_ATTRIB)
+				continue;
+			if (ebitmap_set_bit(t, i, 1))
+				return -1;
+		}
+		goto out;
+	}
+
+	ebitmap_for_each_bit(&types, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)
+		    && (!ebitmap_get_bit(&neg_types, i)))
+			if (ebitmap_set_bit(t, i, 1))
+				return -1;
+	}
+
+	if (set->flags & TYPE_COMP) {
+		for (i = 0; i < p->p_types.nprim; i++) {
+			if (p->type_val_to_struct[i] &&
+			    p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+				assert(!ebitmap_get_bit(t, i));
+				continue;
+			}
+			if (ebitmap_get_bit(t, i)) {
+				if (ebitmap_set_bit(t, i, 0))
+					return -1;
+			} else {
+				if (ebitmap_set_bit(t, i, 1))
+					return -1;
+			}
+		}
+	}
+
+      out:
+
+	ebitmap_destroy(&types);
+	ebitmap_destroy(&neg_types);
+
+	return 0;
+}
+
+static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
+			   avrule_t * source_rule)
+{
+	ebitmap_t stypes, ttypes;
+	avrule_t *avrule;
+	class_perm_node_t *cur_perm, *new_perm, *tail_perm;
+	av_extended_perms_t *xperms = NULL;
+
+	ebitmap_init(&stypes);
+	ebitmap_init(&ttypes);
+
+	if (expand_convert_type_set
+	    (dest_pol, typemap, &source_rule->stypes, &stypes, 1))
+		return -1;
+	if (expand_convert_type_set
+	    (dest_pol, typemap, &source_rule->ttypes, &ttypes, 1))
+		return -1;
+
+	avrule = (avrule_t *) malloc(sizeof(avrule_t));
+	if (!avrule)
+		return -1;
+
+	avrule_init(avrule);
+	avrule->specified = source_rule->specified;
+	avrule->line = source_rule->line;
+	avrule->flags = source_rule->flags;
+	avrule->source_line = source_rule->source_line;
+	if (source_rule->source_filename) {
+		avrule->source_filename = strdup(source_rule->source_filename);
+		if (!avrule->source_filename)
+			goto err;
+	}
+
+	if (ebitmap_cpy(&avrule->stypes.types, &stypes))
+		goto err;
+
+	if (ebitmap_cpy(&avrule->ttypes.types, &ttypes))
+		goto err;
+
+	cur_perm = source_rule->perms;
+	tail_perm = NULL;
+	while (cur_perm) {
+		new_perm =
+		    (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+		if (!new_perm)
+			goto err;
+		class_perm_node_init(new_perm);
+		new_perm->tclass = cur_perm->tclass;
+		assert(new_perm->tclass);
+
+		/* once we have modules with permissions we'll need to map the permissions (and classes) */
+		new_perm->data = cur_perm->data;
+
+		if (!avrule->perms)
+			avrule->perms = new_perm;
+
+		if (tail_perm)
+			tail_perm->next = new_perm;
+		tail_perm = new_perm;
+		cur_perm = cur_perm->next;
+	}
+
+	/* copy over extended permissions */
+	if (source_rule->xperms) {
+		xperms = calloc(1, sizeof(av_extended_perms_t));
+		if (!xperms)
+			goto err;
+		memcpy(xperms, source_rule->xperms, sizeof(av_extended_perms_t));
+		avrule->xperms = xperms;
+	}
+
+	/* just prepend the avrule to the first branch; it'll never be
+	   written to disk */
+	if (!dest_pol->global->branch_list->avrules)
+		dest_pol->global->branch_list->avrules = avrule;
+	else {
+		avrule->next = dest_pol->global->branch_list->avrules;
+		dest_pol->global->branch_list->avrules = avrule;
+	}
+
+	ebitmap_destroy(&stypes);
+	ebitmap_destroy(&ttypes);
+
+	return 0;
+
+      err:
+	ebitmap_destroy(&stypes);
+	ebitmap_destroy(&ttypes);
+	ebitmap_destroy(&avrule->stypes.types);
+	ebitmap_destroy(&avrule->ttypes.types);
+	cur_perm = avrule->perms;
+	while (cur_perm) {
+		tail_perm = cur_perm->next;
+		free(cur_perm);
+		cur_perm = tail_perm;
+	}
+	free(xperms);
+	free(avrule);
+	return -1;
+}
+
+/* 
+ * Expands the avrule blocks for a policy. RBAC rules are copied. Neverallow
+ * rules are copied or expanded as per the settings in the state object; all
+ * other AV rules are expanded.  If neverallow rules are expanded, they are not
+ * copied, otherwise they are copied for later use by the assertion checker.
+ */
+static int copy_and_expand_avrule_block(expand_state_t * state)
+{
+	avrule_block_t *curblock = state->base->global;
+	avrule_block_t *prevblock;
+	int retval = -1;
+
+	if (avtab_alloc(&state->out->te_avtab, MAX_AVTAB_SIZE)) {
+ 		ERR(state->handle, "Out of Memory!");
+ 		return -1;
+ 	}
+ 
+ 	if (avtab_alloc(&state->out->te_cond_avtab, MAX_AVTAB_SIZE)) {
+ 		ERR(state->handle, "Out of Memory!");
+ 		return -1;
+ 	}
+
+	while (curblock) {
+		avrule_decl_t *decl = curblock->enabled;
+		avrule_t *cur_avrule;
+
+		if (decl == NULL) {
+			/* nothing was enabled within this block */
+			goto cont;
+		}
+
+		/* copy role allows and role trans */
+		if (copy_role_allows(state, decl->role_allow_rules) != 0 ||
+		    copy_role_trans(state, decl->role_tr_rules) != 0) {
+			goto cleanup;
+		}
+
+		if (expand_filename_trans(state, decl->filename_trans_rules))
+			goto cleanup;
+
+		/* expand the range transition rules */
+		if (expand_range_trans(state, decl->range_tr_rules))
+			goto cleanup;
+
+		/* copy rules */
+		cur_avrule = decl->avrules;
+		while (cur_avrule != NULL) {
+			if (!(state->expand_neverallow)
+			    && cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)) {
+				/* copy this over directly so that assertions are checked later */
+				if (copy_neverallow
+				    (state->out, state->typemap, cur_avrule))
+					ERR(state->handle,
+					    "Error while copying neverallow.");
+			} else {
+				if (cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))
+					state->out->unsupported_format = 1;
+				if (convert_and_expand_rule
+				    (state->handle, state->out, state->typemap,
+				     cur_avrule, &state->out->te_avtab, NULL,
+				     NULL, 0,
+				     state->expand_neverallow) !=
+				    EXPAND_RULE_SUCCESS) {
+					goto cleanup;
+				}
+			}
+			cur_avrule = cur_avrule->next;
+		}
+
+		/* copy conditional rules */
+		if (cond_node_copy(state, decl->cond_list))
+			goto cleanup;
+
+      cont:
+		prevblock = curblock;
+		curblock = curblock->next;
+
+		if (state->handle && state->handle->expand_consume_base) {
+			/* set base top avrule block in case there
+ 			 * is an error condition and the policy needs 
+ 			 * to be destroyed */
+			state->base->global = curblock;
+			avrule_block_destroy(prevblock);
+		}
+	}
+
+	retval = 0;
+
+      cleanup:
+	return retval;
+}
+
+/* 
+ * This function allows external users of the library (such as setools) to
+ * expand only the avrules and optionally perform expansion of neverallow rules
+ * or expand into the same policy for analysis purposes.
+ */
+int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+			  policydb_t * out, uint32_t * typemap,
+			  uint32_t * boolmap, uint32_t * rolemap,
+			  uint32_t * usermap, int verbose,
+			  int expand_neverallow)
+{
+	expand_state_t state;
+
+	expand_state_init(&state);
+
+	state.base = base;
+	state.out = out;
+	state.typemap = typemap;
+	state.boolmap = boolmap;
+	state.rolemap = rolemap;
+	state.usermap = usermap;
+	state.handle = handle;
+	state.verbose = verbose;
+	state.expand_neverallow = expand_neverallow;
+
+	return copy_and_expand_avrule_block(&state);
+}
+
+static void discard_tunables(sepol_handle_t *sh, policydb_t *pol)
+{
+	avrule_block_t *block;
+	avrule_decl_t *decl;
+	cond_node_t *cur_node;
+	cond_expr_t *cur_expr;
+	int cur_state, preserve_tunables = 0;
+	avrule_t *tail, *to_be_appended;
+
+	if (sh && sh->preserve_tunables)
+		preserve_tunables = 1;
+
+	/* Iterate through all cond_node of all enabled decls, if a cond_node
+	 * is about tunable, calculate its state value and concatenate one of
+	 * its avrule list to the current decl->avrules list. On the other
+	 * hand, the disabled unused branch of a tunable would be discarded.
+	 *
+	 * Note, such tunable cond_node would be skipped over in expansion,
+	 * so we won't have to worry about removing it from decl->cond_list
+	 * here :-)
+	 *
+	 * If tunables are requested to be preserved then they would be
+	 * "transformed" as booleans by having their TUNABLE flag cleared.
+	 */
+	for (block = pol->global; block != NULL; block = block->next) {
+		decl = block->enabled;
+		if (decl == NULL || decl->enabled == 0)
+			continue;
+
+		tail = decl->avrules;
+		while (tail && tail->next)
+			tail = tail->next;
+
+		for (cur_node = decl->cond_list; cur_node != NULL;
+		     cur_node = cur_node->next) {
+			int booleans, tunables, i;
+			cond_bool_datum_t *booldatum;
+			cond_bool_datum_t *tmp[COND_EXPR_MAXDEPTH];
+
+			booleans = tunables = 0;
+			memset(tmp, 0, sizeof(cond_bool_datum_t *) * COND_EXPR_MAXDEPTH);
+
+			for (cur_expr = cur_node->expr; cur_expr != NULL;
+			     cur_expr = cur_expr->next) {
+				if (cur_expr->expr_type != COND_BOOL)
+					continue;
+				booldatum = pol->bool_val_to_struct[cur_expr->bool - 1];
+				if (booldatum->flags & COND_BOOL_FLAGS_TUNABLE)
+					tmp[tunables++] = booldatum;
+				else
+					booleans++;
+			}
+
+			/* bool_copy_callback() at link phase has ensured
+			 * that no mixture of tunables and booleans in one
+			 * expression. However, this would be broken by the
+			 * request to preserve tunables */
+			if (!preserve_tunables)
+				assert(!(booleans && tunables));
+
+			if (booleans || preserve_tunables) {
+				cur_node->flags &= ~COND_NODE_FLAGS_TUNABLE;
+				if (tunables) {
+					for (i = 0; i < tunables; i++)
+						tmp[i]->flags &= ~COND_BOOL_FLAGS_TUNABLE;
+				}
+			} else {
+				cur_node->flags |= COND_NODE_FLAGS_TUNABLE;
+				cur_state = cond_evaluate_expr(pol, cur_node->expr);
+				if (cur_state == -1) {
+					printf("Expression result was "
+					       "undefined, skipping all"
+					       "rules\n");
+					continue;
+				}
+
+				to_be_appended = (cur_state == 1) ?
+					cur_node->avtrue_list : cur_node->avfalse_list;
+
+				if (tail)
+					tail->next = to_be_appended;
+				else
+					tail = decl->avrules = to_be_appended;
+
+				/* Now that the effective branch has been
+				 * appended, neutralize its original pointer */
+				if (cur_state == 1)
+					cur_node->avtrue_list = NULL;
+				else
+					cur_node->avfalse_list = NULL;
+
+				/* Update the tail of decl->avrules for
+				 * further concatenation */
+				while (tail && tail->next)
+					tail = tail->next;
+			}
+		}
+	}
+}
+
+/* Linking should always be done before calling expand, even if
+ * there is only a base since all optionals are dealt with at link time
+ * the base passed in should be indexed and avrule blocks should be 
+ * enabled.
+ */
+int expand_module(sepol_handle_t * handle,
+		  policydb_t * base, policydb_t * out, int verbose, int check)
+{
+	int retval = -1;
+	unsigned int i;
+	expand_state_t state;
+	avrule_block_t *curblock;
+
+	/* Append tunable's avtrue_list or avfalse_list to the avrules list
+	 * of its home decl depending on its state value, so that the effect
+	 * rules of a tunable would be added to te_avtab permanently. Whereas
+	 * the disabled unused branch would be discarded.
+	 *
+	 * Originally this function is called at the very end of link phase,
+	 * however, we need to keep the linked policy intact for analysis
+	 * purpose. */
+	discard_tunables(handle, base);
+
+	expand_state_init(&state);
+
+	state.verbose = verbose;
+	state.typemap = NULL;
+	state.base = base;
+	state.out = out;
+	state.handle = handle;
+
+	if (base->policy_type != POLICY_BASE) {
+		ERR(handle, "Target of expand was not a base policy.");
+		return -1;
+	}
+
+	state.out->policy_type = POLICY_KERN;
+	state.out->policyvers = POLICYDB_VERSION_MAX;
+
+	/* Copy mls state from base to out */
+	out->mls = base->mls;
+	out->handle_unknown = base->handle_unknown;
+
+	/* Copy target from base to out */
+	out->target_platform = base->target_platform;
+
+	/* Copy policy capabilities */
+	if (ebitmap_cpy(&out->policycaps, &base->policycaps)) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+
+	if ((state.typemap =
+	     (uint32_t *) calloc(state.base->p_types.nprim,
+				 sizeof(uint32_t))) == NULL) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+
+	state.boolmap = (uint32_t *)calloc(state.base->p_bools.nprim, sizeof(uint32_t));
+	if (!state.boolmap) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+
+	state.rolemap = (uint32_t *)calloc(state.base->p_roles.nprim, sizeof(uint32_t));
+	if (!state.rolemap) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+
+	state.usermap = (uint32_t *)calloc(state.base->p_users.nprim, sizeof(uint32_t));
+	if (!state.usermap) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+
+	/* order is important - types must be first */
+
+	/* copy types */
+	if (hashtab_map(state.base->p_types.table, type_copy_callback, &state)) {
+		goto cleanup;
+	}
+
+	/* convert attribute type sets */
+	if (hashtab_map
+	    (state.base->p_types.table, attr_convert_callback, &state)) {
+		goto cleanup;
+	}
+
+	/* copy commons */
+	if (hashtab_map
+	    (state.base->p_commons.table, common_copy_callback, &state)) {
+		goto cleanup;
+	}
+
+	/* copy classes, note, this does not copy constraints, constraints can't be
+	 * copied until after all the blocks have been processed and attributes are complete */
+	if (hashtab_map
+	    (state.base->p_classes.table, class_copy_callback, &state)) {
+		goto cleanup;
+	}
+
+	/* copy type bounds */
+	if (hashtab_map(state.base->p_types.table,
+			type_bounds_copy_callback, &state))
+		goto cleanup;
+
+	/* copy aliases */
+	if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
+		goto cleanup;
+
+	/* index here so that type indexes are available for role_copy_callback */
+	if (policydb_index_others(handle, out, verbose)) {
+		ERR(handle, "Error while indexing out symbols");
+		goto cleanup;
+	}
+
+	/* copy roles */
+	if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state))
+		goto cleanup;
+	if (hashtab_map(state.base->p_roles.table,
+			role_bounds_copy_callback, &state))
+		goto cleanup;
+	/* escalate the type_set_t in a role attribute to all regular roles
+	 * that belongs to it. */
+	if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state))
+		goto cleanup;
+
+	/* copy MLS's sensitivity level and categories - this needs to be done
+	 * before expanding users (they need to be indexed too) */
+	if (hashtab_map(state.base->p_levels.table, sens_copy_callback, &state))
+		goto cleanup;
+	if (hashtab_map(state.base->p_cats.table, cats_copy_callback, &state))
+		goto cleanup;
+	if (policydb_index_others(handle, out, verbose)) {
+		ERR(handle, "Error while indexing out symbols");
+		goto cleanup;
+	}
+
+	/* copy users */
+	if (hashtab_map(state.base->p_users.table, user_copy_callback, &state))
+		goto cleanup;
+	if (hashtab_map(state.base->p_users.table,
+			user_bounds_copy_callback, &state))
+		goto cleanup;
+
+	/* copy bools */
+	if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state))
+		goto cleanup;
+
+	if (policydb_index_classes(out)) {
+		ERR(handle, "Error while indexing out classes");
+		goto cleanup;
+	}
+	if (policydb_index_others(handle, out, verbose)) {
+		ERR(handle, "Error while indexing out symbols");
+		goto cleanup;
+	}
+
+	/* loop through all decls and union attributes, roles, users */
+	for (curblock = state.base->global; curblock != NULL;
+	     curblock = curblock->next) {
+		avrule_decl_t *decl = curblock->enabled;
+
+		if (decl == NULL) {
+			/* nothing was enabled within this block */
+			continue;
+		}
+
+		/* convert attribute type sets */
+		if (hashtab_map
+		    (decl->p_types.table, attr_convert_callback, &state)) {
+			goto cleanup;
+		}
+
+		/* copy roles */
+		if (hashtab_map
+		    (decl->p_roles.table, role_copy_callback, &state))
+			goto cleanup;
+
+		/* copy users */
+		if (hashtab_map
+		    (decl->p_users.table, user_copy_callback, &state))
+			goto cleanup;
+
+	}
+
+	/* remap role dominates bitmaps */
+	 if (hashtab_map(state.out->p_roles.table, role_remap_dominates, &state)) {
+		goto cleanup;
+	}
+
+	if (copy_and_expand_avrule_block(&state) < 0) {
+		ERR(handle, "Error during expand");
+		goto cleanup;
+	}
+
+	/* copy constraints */
+	if (hashtab_map
+	    (state.base->p_classes.table, constraint_copy_callback, &state)) {
+		goto cleanup;
+	}
+
+	cond_optimize_lists(state.out->cond_list);
+	if (evaluate_conds(state.out))
+		goto cleanup;
+
+	/* copy ocontexts */
+	if (ocontext_copy(&state, out->target_platform))
+		goto cleanup;
+
+	/* copy genfs */
+	if (genfs_copy(&state))
+		goto cleanup;
+
+	/* Build the type<->attribute maps and remove attributes. */
+	state.out->attr_type_map = malloc(state.out->p_types.nprim *
+					  sizeof(ebitmap_t));
+	state.out->type_attr_map = malloc(state.out->p_types.nprim *
+					  sizeof(ebitmap_t));
+	if (!state.out->attr_type_map || !state.out->type_attr_map) {
+		ERR(handle, "Out of memory!");
+		goto cleanup;
+	}
+	for (i = 0; i < state.out->p_types.nprim; i++) {
+		ebitmap_init(&state.out->type_attr_map[i]);
+		ebitmap_init(&state.out->attr_type_map[i]);
+		/* add the type itself as the degenerate case */
+		if (ebitmap_set_bit(&state.out->type_attr_map[i], i, 1)) {
+			ERR(handle, "Out of memory!");
+			goto cleanup;
+		}
+	}
+	if (hashtab_map(state.out->p_types.table, type_attr_map, &state))
+		goto cleanup;
+	if (check) {
+		if (hierarchy_check_constraints(handle, state.out))
+			goto cleanup;
+
+		if (check_assertions
+		    (handle, state.out,
+		     state.out->global->branch_list->avrules))
+			 goto cleanup;
+	}
+
+	retval = 0;
+
+      cleanup:
+	free(state.typemap);
+	free(state.boolmap);
+	free(state.rolemap);
+	free(state.usermap);
+	return retval;
+}
+
+static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
+{
+	avtab_ptr_t node;
+	avtab_datum_t *avd;
+	avtab_extended_perms_t *xperms;
+	unsigned int i;
+	unsigned int match = 0;
+
+	if (k->specified & AVTAB_XPERMS) {
+		/*
+		 * AVTAB_XPERMS entries are not necessarily unique.
+		 * find node with matching xperms
+		 */
+		node = avtab_search_node(a, k);
+		while (node) {
+			if ((node->datum.xperms->specified == d->xperms->specified) &&
+				(node->datum.xperms->driver == d->xperms->driver)) {
+				match = 1;
+				break;
+			}
+			node = avtab_search_node_next(node, k->specified);
+		}
+		if (!match)
+			node = NULL;
+	} else {
+		node = avtab_search_node(a, k);
+	}
+
+	if (!node || ((k->specified & AVTAB_ENABLED) !=
+			(node->key.specified & AVTAB_ENABLED))) {
+		node = avtab_insert_nonunique(a, k, d);
+		if (!node) {
+			ERR(NULL, "Out of memory!");
+			return -1;
+		}
+		return 0;
+	}
+
+	avd = &node->datum;
+	xperms = node->datum.xperms;
+	switch (k->specified & ~AVTAB_ENABLED) {
+	case AVTAB_ALLOWED:
+	case AVTAB_AUDITALLOW:
+		avd->data |= d->data;
+		break;
+	case AVTAB_AUDITDENY:
+		avd->data &= d->data;
+		break;
+	case AVTAB_XPERMS_ALLOWED:
+	case AVTAB_XPERMS_AUDITALLOW:
+	case AVTAB_XPERMS_DONTAUDIT:
+		for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+			xperms->perms[i] |= d->xperms->perms[i];
+		break;
+	default:
+		ERR(NULL, "Type conflict!");
+		return -1;
+	}
+
+	return 0;
+}
+
+struct expand_avtab_data {
+	avtab_t *expa;
+	policydb_t *p;
+
+};
+
+static int expand_avtab_node(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+	struct expand_avtab_data *ptr = args;
+	avtab_t *expa = ptr->expa;
+	policydb_t *p = ptr->p;
+	type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+	type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+	ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+	ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+	avtab_key_t newkey;
+	int rc;
+
+	newkey.target_class = k->target_class;
+	newkey.specified = k->specified;
+
+	if (stype && ttype && stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) {
+		/* Both are individual types, no expansion required. */
+		return expand_avtab_insert(expa, k, d);
+	}
+
+	if (stype && stype->flavor != TYPE_ATTRIB) {
+		/* Source is an individual type, target is an attribute. */
+		newkey.source_type = k->source_type;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			newkey.target_type = j + 1;
+			rc = expand_avtab_insert(expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+		return 0;
+	}
+
+	if (ttype && ttype->flavor != TYPE_ATTRIB) {
+		/* Target is an individual type, source is an attribute. */
+		newkey.target_type = k->target_type;
+		ebitmap_for_each_bit(sattr, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			newkey.source_type = i + 1;
+			rc = expand_avtab_insert(expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+		return 0;
+	}
+
+	/* Both source and target type are attributes. */
+	ebitmap_for_each_bit(sattr, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			newkey.source_type = i + 1;
+			newkey.target_type = j + 1;
+			rc = expand_avtab_insert(expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa)
+{
+	struct expand_avtab_data data;
+
+	if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+		ERR(NULL, "Out of memory!");
+		return -1;
+	}
+
+	data.expa = expa;
+	data.p = p;
+	return avtab_map(a, expand_avtab_node, &data);
+}
+
+static int expand_cond_insert(cond_av_list_t ** l,
+			      avtab_t * expa,
+			      avtab_key_t * k, avtab_datum_t * d)
+{
+	avtab_ptr_t node;
+	avtab_datum_t *avd;
+	cond_av_list_t *nl;
+
+	node = avtab_search_node(expa, k);
+	if (!node ||
+	    (k->specified & AVTAB_ENABLED) !=
+	    (node->key.specified & AVTAB_ENABLED)) {
+		node = avtab_insert_nonunique(expa, k, d);
+		if (!node) {
+			ERR(NULL, "Out of memory!");
+			return -1;
+		}
+		node->parse_context = (void *)1;
+		nl = (cond_av_list_t *) malloc(sizeof(*nl));
+		if (!nl) {
+			ERR(NULL, "Out of memory!");
+			return -1;
+		}
+		memset(nl, 0, sizeof(*nl));
+		nl->node = node;
+		nl->next = *l;
+		*l = nl;
+		return 0;
+	}
+
+	avd = &node->datum;
+	switch (k->specified & ~AVTAB_ENABLED) {
+	case AVTAB_ALLOWED:
+	case AVTAB_AUDITALLOW:
+		avd->data |= d->data;
+		break;
+	case AVTAB_AUDITDENY:
+		avd->data &= d->data;
+		break;
+	default:
+		ERR(NULL, "Type conflict!");
+		return -1;
+	}
+
+	return 0;
+}
+
+int expand_cond_av_node(policydb_t * p,
+			avtab_ptr_t node,
+			cond_av_list_t ** newl, avtab_t * expa)
+{
+	avtab_key_t *k = &node->key;
+	avtab_datum_t *d = &node->datum;
+	type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+	type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+	ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+	ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+	avtab_key_t newkey;
+	int rc;
+
+	newkey.target_class = k->target_class;
+	newkey.specified = k->specified;
+
+	if (stype && ttype && stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) {
+		/* Both are individual types, no expansion required. */
+		return expand_cond_insert(newl, expa, k, d);
+	}
+
+	if (stype && stype->flavor != TYPE_ATTRIB) {
+		/* Source is an individual type, target is an attribute. */
+		newkey.source_type = k->source_type;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			newkey.target_type = j + 1;
+			rc = expand_cond_insert(newl, expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+		return 0;
+	}
+
+	if (ttype && ttype->flavor != TYPE_ATTRIB) {
+		/* Target is an individual type, source is an attribute. */
+		newkey.target_type = k->target_type;
+		ebitmap_for_each_bit(sattr, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			newkey.source_type = i + 1;
+			rc = expand_cond_insert(newl, expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+		return 0;
+	}
+
+	/* Both source and target type are attributes. */
+	ebitmap_for_each_bit(sattr, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			newkey.source_type = i + 1;
+			newkey.target_type = j + 1;
+			rc = expand_cond_insert(newl, expa, &newkey, d);
+			if (rc)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+			cond_av_list_t ** newl, avtab_t * expa)
+{
+	cond_av_list_t *cur;
+	avtab_ptr_t node;
+	int rc;
+
+	if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+		ERR(NULL, "Out of memory!");
+		return -1;
+	}
+
+	*newl = NULL;
+	for (cur = l; cur; cur = cur->next) {
+		node = cur->node;
+		rc = expand_cond_av_node(p, node, newl, expa);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
diff --git a/libsepol/src/genbools.c b/libsepol/src/genbools.c
new file mode 100644
index 0000000..c81e848
--- /dev/null
+++ b/libsepol/src/genbools.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+
+/* -- Deprecated -- */
+
+static char *strtrim(char *dest, char *source, int size)
+{
+	int i = 0;
+	char *ptr = source;
+	i = 0;
+	while (isspace(*ptr) && i < size) {
+		ptr++;
+		i++;
+	}
+	strncpy(dest, ptr, size);
+	for (i = strlen(dest) - 1; i > 0; i--) {
+		if (!isspace(dest[i]))
+			break;
+	}
+	dest[i + 1] = '\0';
+	return dest;
+}
+
+static int process_boolean(char *buffer, char *name, int namesize, int *val)
+{
+	char name1[BUFSIZ];
+	char *ptr = NULL;
+	char *tok = strtok_r(buffer, "=", &ptr);
+	if (tok) {
+		strncpy(name1, tok, BUFSIZ - 1);
+		strtrim(name, name1, namesize - 1);
+		if (name[0] == '#')
+			return 0;
+		tok = strtok_r(NULL, "\0", &ptr);
+		if (tok) {
+			while (isspace(*tok))
+				tok++;
+			*val = -1;
+			if (isdigit(tok[0]))
+				*val = atoi(tok);
+			else if (!strncasecmp(tok, "true", sizeof("true") - 1))
+				*val = 1;
+			else if (!strncasecmp
+				 (tok, "false", sizeof("false") - 1))
+				*val = 0;
+			if (*val != 0 && *val != 1) {
+				ERR(NULL, "illegal value for boolean "
+				    "%s=%s", name, tok);
+				return -1;
+			}
+
+		}
+	}
+	return 1;
+}
+
+static int load_booleans(struct policydb *policydb, const char *path,
+			 int *changesp)
+{
+	FILE *boolf;
+	char *buffer = NULL;
+	size_t size = 0;
+	char localbools[BUFSIZ];
+	char name[BUFSIZ];
+	int val;
+	int errors = 0, changes = 0;
+	struct cond_bool_datum *datum;
+
+	boolf = fopen(path, "r");
+	if (boolf == NULL)
+		goto localbool;
+
+#ifdef __APPLE__
+        if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
+          ERR(NULL, "out of memory");
+	  return -1;
+	}
+
+        while(fgets(buffer, 255, boolf) != NULL) {
+#else
+	while (getline(&buffer, &size, boolf) > 0) {
+#endif
+		int ret = process_boolean(buffer, name, sizeof(name), &val);
+		if (ret == -1)
+			errors++;
+		if (ret == 1) {
+			datum = hashtab_search(policydb->p_bools.table, name);
+			if (!datum) {
+				ERR(NULL, "unknown boolean %s", name);
+				errors++;
+				continue;
+			}
+			if (datum->state != val) {
+				datum->state = val;
+				changes++;
+			}
+		}
+	}
+	fclose(boolf);
+      localbool:
+	snprintf(localbools, sizeof(localbools), "%s.local", path);
+	boolf = fopen(localbools, "r");
+	if (boolf != NULL) {
+
+#ifdef __APPLE__
+
+	  while(fgets(buffer, 255, boolf) != NULL) {
+#else
+
+	    while (getline(&buffer, &size, boolf) > 0) {
+#endif
+			int ret =
+			    process_boolean(buffer, name, sizeof(name), &val);
+			if (ret == -1)
+				errors++;
+			if (ret == 1) {
+				datum =
+				    hashtab_search(policydb->p_bools.table,
+						   name);
+				if (!datum) {
+					ERR(NULL, "unknown boolean %s", name);
+					errors++;
+					continue;
+				}
+				if (datum->state != val) {
+					datum->state = val;
+					changes++;
+				}
+			}
+		}
+		fclose(boolf);
+	}
+	free(buffer);
+	if (errors)
+		errno = EINVAL;
+	*changesp = changes;
+	return errors ? -1 : 0;
+}
+
+int sepol_genbools(void *data, size_t len, char *booleans)
+{
+	struct policydb policydb;
+	struct policy_file pf;
+	int rc, changes = 0;
+
+	if (policydb_init(&policydb))
+		goto err;
+	if (policydb_from_image(NULL, data, len, &policydb) < 0)
+		goto err;
+
+	if (load_booleans(&policydb, booleans, &changes) < 0) {
+		WARN(NULL, "error while reading %s", booleans);
+	}
+
+	if (!changes)
+		goto out;
+
+	if (evaluate_conds(&policydb) < 0) {
+		ERR(NULL, "error while re-evaluating conditionals");
+		errno = EINVAL;
+		goto err_destroy;
+	}
+
+	policy_file_init(&pf);
+	pf.type = PF_USE_MEMORY;
+	pf.data = data;
+	pf.len = len;
+	rc = policydb_write(&policydb, &pf);
+	if (rc) {
+		ERR(NULL, "unable to write new binary policy image");
+		errno = EINVAL;
+		goto err_destroy;
+	}
+
+      out:
+	policydb_destroy(&policydb);
+	return 0;
+
+      err_destroy:
+	policydb_destroy(&policydb);
+
+      err:
+	return -1;
+}
+
+int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
+{
+	int rc, changes = 0;
+
+	rc = load_booleans(policydb, booleans, &changes);
+	if (!rc && changes)
+		rc = evaluate_conds(policydb);
+	if (rc)
+		errno = EINVAL;
+	return rc;
+}
+
+/* -- End Deprecated -- */
+
+int sepol_genbools_array(void *data, size_t len, char **names, int *values,
+			 int nel)
+{
+	struct policydb policydb;
+	struct policy_file pf;
+	int rc, i, errors = 0;
+	struct cond_bool_datum *datum;
+
+	/* Create policy database from image */
+	if (policydb_init(&policydb))
+		goto err;
+	if (policydb_from_image(NULL, data, len, &policydb) < 0)
+		goto err;
+
+	for (i = 0; i < nel; i++) {
+		datum = hashtab_search(policydb.p_bools.table, names[i]);
+		if (!datum) {
+			ERR(NULL, "boolean %s no longer in policy", names[i]);
+			errors++;
+			continue;
+		}
+		if (values[i] != 0 && values[i] != 1) {
+			ERR(NULL, "illegal value %d for boolean %s",
+			    values[i], names[i]);
+			errors++;
+			continue;
+		}
+		datum->state = values[i];
+	}
+
+	if (evaluate_conds(&policydb) < 0) {
+		ERR(NULL, "error while re-evaluating conditionals");
+		errno = EINVAL;
+		goto err_destroy;
+	}
+
+	policy_file_init(&pf);
+	pf.type = PF_USE_MEMORY;
+	pf.data = data;
+	pf.len = len;
+	rc = policydb_write(&policydb, &pf);
+	if (rc) {
+		ERR(NULL, "unable to write binary policy");
+		errno = EINVAL;
+		goto err_destroy;
+	}
+	if (errors) {
+		errno = EINVAL;
+		goto err_destroy;
+	}
+
+	policydb_destroy(&policydb);
+	return 0;
+
+      err_destroy:
+	policydb_destroy(&policydb);
+
+      err:
+	return -1;
+}
diff --git a/libsepol/src/genusers.c b/libsepol/src/genusers.c
new file mode 100644
index 0000000..0b98a76
--- /dev/null
+++ b/libsepol/src/genusers.c
@@ -0,0 +1,343 @@
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sepol/policydb/policydb.h>
+
+#ifndef __APPLE__
+#include <stdio_ext.h>
+#endif
+
+#include <stdarg.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+#include "mls.h"
+
+/* -- Deprecated -- */
+
+void sepol_set_delusers(int on __attribute((unused)))
+{
+	WARN(NULL, "Deprecated interface");
+}
+
+#undef BADLINE
+#define BADLINE() { \
+	ERR(NULL, "invalid entry %s (%s:%u)", \
+		buffer, path, lineno); \
+	continue; \
+}
+
+static int load_users(struct policydb *policydb, const char *path)
+{
+	FILE *fp;
+	char *buffer = NULL, *p, *q, oldc;
+	size_t len = 0;
+	ssize_t nread;
+	unsigned lineno = 0, islist = 0, bit;
+	user_datum_t *usrdatum;
+	role_datum_t *roldatum;
+	ebitmap_node_t *rnode;
+
+	fp = fopen(path, "r");
+	if (fp == NULL)
+		return -1;
+
+#ifdef __APPLE__
+	if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
+	  ERR(NULL, "out of memory");
+	  return -1;
+	}
+
+	while(fgets(buffer, 255, fp) != NULL) {
+#else
+	__fsetlocking(fp, FSETLOCKING_BYCALLER);
+	while ((nread = getline(&buffer, &len, fp)) > 0) {
+#endif
+
+		lineno++;
+		if (buffer[nread - 1] == '\n')
+			buffer[nread - 1] = 0;
+		p = buffer;
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p) || *p == '#')
+			continue;
+
+		if (strncasecmp(p, "user", 4))
+			BADLINE();
+		p += 4;
+		if (!isspace(*p))
+			BADLINE();
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		q = p;
+		while (*p && !isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		*p++ = 0;
+
+		usrdatum = hashtab_search(policydb->p_users.table, q);
+		if (usrdatum) {
+			/* Replacing an existing user definition. */
+			ebitmap_destroy(&usrdatum->roles.roles);
+			ebitmap_init(&usrdatum->roles.roles);
+		} else {
+			char *id = strdup(q);
+
+			if (!id) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				fclose(fp);
+				return -1;
+			}
+
+			/* Adding a new user definition. */
+			usrdatum = malloc(sizeof(user_datum_t));
+			if (!usrdatum) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				free(id);
+				fclose(fp);
+				return -1;
+			}
+
+			user_datum_init(usrdatum);
+			usrdatum->s.value = ++policydb->p_users.nprim;
+			if (hashtab_insert(policydb->p_users.table,
+					   id, (hashtab_datum_t) usrdatum)) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				free(id);
+				user_datum_destroy(usrdatum);
+				free(usrdatum);
+				fclose(fp);
+				return -1;
+			}
+		}
+
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		if (strncasecmp(p, "roles", 5))
+			BADLINE();
+		p += 5;
+		if (!isspace(*p))
+			BADLINE();
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		if (*p == '{') {
+			islist = 1;
+			p++;
+		} else
+			islist = 0;
+
+		oldc = 0;
+		do {
+			while (*p && isspace(*p))
+				p++;
+			if (!(*p))
+				break;
+
+			q = p;
+			while (*p && *p != ';' && *p != '}' && !isspace(*p))
+				p++;
+			if (!(*p))
+				break;
+			if (*p == '}')
+				islist = 0;
+			oldc = *p;
+			*p++ = 0;
+			if (!q[0])
+				break;
+
+			roldatum = hashtab_search(policydb->p_roles.table, q);
+			if (!roldatum) {
+				ERR(NULL, "undefined role %s (%s:%u)",
+				    q, path, lineno);
+				continue;
+			}
+			/* Set the role and every role it dominates */
+			ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+				if (ebitmap_node_get_bit(rnode, bit))
+					if (ebitmap_set_bit
+					    (&usrdatum->roles.roles, bit, 1)) {
+						ERR(NULL, "out of memory");
+						free(buffer);
+						fclose(fp);
+						return -1;
+					}
+			}
+		} while (islist);
+		if (oldc == 0)
+			BADLINE();
+
+		if (policydb->mls) {
+			context_struct_t context;
+			char *scontext, *r, *s;
+
+			while (*p && isspace(*p))
+				p++;
+			if (!(*p))
+				BADLINE();
+			if (strncasecmp(p, "level", 5))
+				BADLINE();
+			p += 5;
+			if (!isspace(*p))
+				BADLINE();
+			while (*p && isspace(*p))
+				p++;
+			if (!(*p))
+				BADLINE();
+			q = p;
+			while (*p && strncasecmp(p, "range", 5))
+				p++;
+			if (!(*p))
+				BADLINE();
+			*--p = 0;
+			p++;
+
+			scontext = malloc(p - q);
+			if (!scontext) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				fclose(fp);
+				return -1;
+			}
+			r = scontext;
+			s = q;
+			while (*s) {
+				if (!isspace(*s))
+					*r++ = *s;
+				s++;
+			}
+			*r = 0;
+			r = scontext;
+
+			context_init(&context);
+			if (mls_context_to_sid(policydb, oldc, &r, &context) <
+			    0) {
+				ERR(NULL, "invalid level %s (%s:%u)", scontext,
+				    path, lineno);
+				free(scontext);
+				continue;
+
+			}
+			free(scontext);
+			memcpy(&usrdatum->dfltlevel, &context.range.level[0],
+			       sizeof(usrdatum->dfltlevel));
+
+			if (strncasecmp(p, "range", 5))
+				BADLINE();
+			p += 5;
+			if (!isspace(*p))
+				BADLINE();
+			while (*p && isspace(*p))
+				p++;
+			if (!(*p))
+				BADLINE();
+			q = p;
+			while (*p && *p != ';')
+				p++;
+			if (!(*p))
+				BADLINE();
+			*p++ = 0;
+
+			scontext = malloc(p - q);
+			if (!scontext) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				fclose(fp);
+				return -1;
+			}
+			r = scontext;
+			s = q;
+			while (*s) {
+				if (!isspace(*s))
+					*r++ = *s;
+				s++;
+			}
+			*r = 0;
+			r = scontext;
+
+			context_init(&context);
+			if (mls_context_to_sid(policydb, oldc, &r, &context) <
+			    0) {
+				ERR(NULL, "invalid range %s (%s:%u)", scontext,
+				    path, lineno);
+				free(scontext);
+				continue;
+			}
+			free(scontext);
+			memcpy(&usrdatum->range, &context.range,
+			       sizeof(usrdatum->range));
+		}
+	}
+
+	free(buffer);
+	fclose(fp);
+	return 0;
+}
+
+int sepol_genusers(void *data, size_t len,
+		   const char *usersdir, void **newdata, size_t * newlen)
+{
+	struct policydb policydb;
+	char path[PATH_MAX];
+
+	/* Construct policy database */
+	if (policydb_init(&policydb))
+		goto err;
+	if (policydb_from_image(NULL, data, len, &policydb) < 0)
+		goto err;
+
+	/* Load locally defined users. */
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+	if (load_users(&policydb, path) < 0)
+		goto err_destroy;
+
+	/* Write policy database */
+	if (policydb_to_image(NULL, &policydb, newdata, newlen) < 0)
+		goto err_destroy;
+
+	policydb_destroy(&policydb);
+	return 0;
+
+      err_destroy:
+	policydb_destroy(&policydb);
+
+      err:
+	return -1;
+}
+
+int hidden sepol_genusers_policydb(policydb_t * policydb, const char *usersdir)
+{
+	char path[PATH_MAX];
+
+	/* Load locally defined users. */
+	snprintf(path, sizeof path, "%s/local.users", usersdir);
+	if (load_users(policydb, path) < 0) {
+		ERR(NULL, "unable to load local.users: %s", strerror(errno));
+		return -1;
+	}
+
+	if (policydb_reindex_users(policydb) < 0) {
+		ERR(NULL, "unable to reindex users: %s", strerror(errno));
+		return -1;
+
+	}
+
+	return 0;
+}
+
+/* -- End Deprecated -- */
diff --git a/libsepol/src/handle.c b/libsepol/src/handle.c
new file mode 100644
index 0000000..2e9a4ad
--- /dev/null
+++ b/libsepol/src/handle.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "handle.h"
+#include "debug.h"
+
+sepol_handle_t *sepol_handle_create(void)
+{
+
+	sepol_handle_t *sh = malloc(sizeof(sepol_handle_t));
+	if (sh == NULL)
+		return NULL;
+
+	/* Set callback */
+	sh->msg_callback = sepol_msg_default_handler;
+	sh->msg_callback_arg = NULL;
+
+	/* by default do not disable dontaudits */
+	sh->disable_dontaudit = 0;
+	sh->expand_consume_base = 0;
+
+	/* by default needless unused branch of tunables would be discarded  */
+	sh->preserve_tunables = 0;
+
+	return sh;
+}
+
+int sepol_get_preserve_tunables(sepol_handle_t *sh)
+{
+	assert(sh != NULL);
+	return sh->preserve_tunables;
+}
+
+void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables)
+{
+	assert(sh !=NULL);
+	sh->preserve_tunables = preserve_tunables;
+}
+
+int sepol_get_disable_dontaudit(sepol_handle_t *sh)
+{
+	assert(sh !=NULL);
+	return sh->disable_dontaudit;
+}
+
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit)
+{
+	assert(sh !=NULL);
+	sh->disable_dontaudit = disable_dontaudit;
+}
+
+void sepol_set_expand_consume_base(sepol_handle_t *sh, int consume_base)
+{
+	assert(sh != NULL);
+	sh->expand_consume_base = consume_base;
+}
+
+void sepol_handle_destroy(sepol_handle_t * sh)
+{
+	free(sh);
+}
diff --git a/libsepol/src/handle.h b/libsepol/src/handle.h
new file mode 100644
index 0000000..7728d04
--- /dev/null
+++ b/libsepol/src/handle.h
@@ -0,0 +1,23 @@
+#ifndef _SEPOL_INTERNAL_HANDLE_H_
+#define _SEPOL_INTERNAL_HANDLE_H_
+
+#include <sepol/handle.h>
+
+struct sepol_handle {
+	/* Error handling */
+	int msg_level;
+	const char *msg_channel;
+	const char *msg_fname;
+#ifdef __GNUC__
+	__attribute__ ((format(printf, 3, 4)))
+#endif
+	void (*msg_callback) (void *varg,
+			      sepol_handle_t * handle, const char *fmt, ...);
+	void *msg_callback_arg;
+
+	int disable_dontaudit;
+	int expand_consume_base;
+	int preserve_tunables;
+};
+
+#endif
diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
new file mode 100644
index 0000000..c4be72c
--- /dev/null
+++ b/libsepol/src/hashtab.c
@@ -0,0 +1,313 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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
+ */
+
+
+/* FLASK */
+
+/*
+ * Implementation of the hash table type.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+
+hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+						     const hashtab_key_t key),
+			 int (*keycmp) (hashtab_t h,
+					const hashtab_key_t key1,
+					const hashtab_key_t key2),
+			 unsigned int size)
+{
+
+	hashtab_t p;
+	unsigned int i;
+
+	p = (hashtab_t) malloc(sizeof(hashtab_val_t));
+	if (p == NULL)
+		return p;
+
+	memset(p, 0, sizeof(hashtab_val_t));
+	p->size = size;
+	p->nel = 0;
+	p->hash_value = hash_value;
+	p->keycmp = keycmp;
+	p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
+	if (p->htable == NULL) {
+		free(p);
+		return NULL;
+	}
+	for (i = 0; i < size; i++)
+		p->htable[i] = (hashtab_ptr_t) NULL;
+
+	return p;
+}
+
+int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
+{
+	int hvalue;
+	hashtab_ptr_t prev, cur, newnode;
+
+	if (!h)
+		return SEPOL_ENOMEM;
+
+	hvalue = h->hash_value(h, key);
+	prev = NULL;
+	cur = h->htable[hvalue];
+	while (cur && h->keycmp(h, key, cur->key) > 0) {
+		prev = cur;
+		cur = cur->next;
+	}
+
+	if (cur && (h->keycmp(h, key, cur->key) == 0))
+		return SEPOL_EEXIST;
+
+	newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+	if (newnode == NULL)
+		return SEPOL_ENOMEM;
+	memset(newnode, 0, sizeof(struct hashtab_node));
+	newnode->key = key;
+	newnode->datum = datum;
+	if (prev) {
+		newnode->next = prev->next;
+		prev->next = newnode;
+	} else {
+		newnode->next = h->htable[hvalue];
+		h->htable[hvalue] = newnode;
+	}
+
+	h->nel++;
+	return SEPOL_OK;
+}
+
+int hashtab_remove(hashtab_t h, hashtab_key_t key,
+		   void (*destroy) (hashtab_key_t k,
+				    hashtab_datum_t d, void *args), void *args)
+{
+	int hvalue;
+	hashtab_ptr_t cur, last;
+
+	if (!h)
+		return SEPOL_ENOENT;
+
+	hvalue = h->hash_value(h, key);
+	last = NULL;
+	cur = h->htable[hvalue];
+	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+		last = cur;
+		cur = cur->next;
+	}
+
+	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+		return SEPOL_ENOENT;
+
+	if (last == NULL)
+		h->htable[hvalue] = cur->next;
+	else
+		last->next = cur->next;
+
+	if (destroy)
+		destroy(cur->key, cur->datum, args);
+	free(cur);
+	h->nel--;
+	return SEPOL_OK;
+}
+
+int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum,
+		    void (*destroy) (hashtab_key_t k,
+				     hashtab_datum_t d, void *args), void *args)
+{
+	int hvalue;
+	hashtab_ptr_t prev, cur, newnode;
+
+	if (!h)
+		return SEPOL_ENOMEM;
+
+	hvalue = h->hash_value(h, key);
+	prev = NULL;
+	cur = h->htable[hvalue];
+	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+		prev = cur;
+		cur = cur->next;
+	}
+
+	if (cur && (h->keycmp(h, key, cur->key) == 0)) {
+		if (destroy)
+			destroy(cur->key, cur->datum, args);
+		cur->key = key;
+		cur->datum = datum;
+	} else {
+		newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+		if (newnode == NULL)
+			return SEPOL_ENOMEM;
+		memset(newnode, 0, sizeof(struct hashtab_node));
+		newnode->key = key;
+		newnode->datum = datum;
+		if (prev) {
+			newnode->next = prev->next;
+			prev->next = newnode;
+		} else {
+			newnode->next = h->htable[hvalue];
+			h->htable[hvalue] = newnode;
+		}
+	}
+
+	return SEPOL_OK;
+}
+
+hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key)
+{
+
+	int hvalue;
+	hashtab_ptr_t cur;
+
+	if (!h)
+		return NULL;
+
+	hvalue = h->hash_value(h, key);
+	cur = h->htable[hvalue];
+	while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+		cur = cur->next;
+
+	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+		return NULL;
+
+	return cur->datum;
+}
+
+void hashtab_destroy(hashtab_t h)
+{
+	unsigned int i;
+	hashtab_ptr_t cur, temp;
+
+	if (!h)
+		return;
+
+	for (i = 0; i < h->size; i++) {
+		cur = h->htable[i];
+		while (cur != NULL) {
+			temp = cur;
+			cur = cur->next;
+			free(temp);
+		}
+		h->htable[i] = NULL;
+	}
+
+	free(h->htable);
+	h->htable = NULL;
+
+	free(h);
+}
+
+int hashtab_map(hashtab_t h,
+		int (*apply) (hashtab_key_t k,
+			      hashtab_datum_t d, void *args), void *args)
+{
+	unsigned int i, ret;
+	hashtab_ptr_t cur;
+
+	if (!h)
+		return SEPOL_OK;
+
+	for (i = 0; i < h->size; i++) {
+		cur = h->htable[i];
+		while (cur != NULL) {
+			ret = apply(cur->key, cur->datum, args);
+			if (ret)
+				return ret;
+			cur = cur->next;
+		}
+	}
+	return SEPOL_OK;
+}
+
+void hashtab_map_remove_on_error(hashtab_t h,
+				 int (*apply) (hashtab_key_t k,
+					       hashtab_datum_t d,
+					       void *args),
+				 void (*destroy) (hashtab_key_t k,
+						  hashtab_datum_t d,
+						  void *args), void *args)
+{
+	unsigned int i;
+	int ret;
+	hashtab_ptr_t last, cur, temp;
+
+	if (!h)
+		return;
+
+	for (i = 0; i < h->size; i++) {
+		last = NULL;
+		cur = h->htable[i];
+		while (cur != NULL) {
+			ret = apply(cur->key, cur->datum, args);
+			if (ret) {
+				if (last) {
+					last->next = cur->next;
+				} else {
+					h->htable[i] = cur->next;
+				}
+
+				temp = cur;
+				cur = cur->next;
+				if (destroy)
+					destroy(temp->key, temp->datum, args);
+				free(temp);
+				h->nel--;
+			} else {
+				last = cur;
+				cur = cur->next;
+			}
+		}
+	}
+
+	return;
+}
+
+void hashtab_hash_eval(hashtab_t h, char *tag)
+{
+	unsigned int i;
+	int chain_len, slots_used, max_chain_len;
+	hashtab_ptr_t cur;
+
+	slots_used = 0;
+	max_chain_len = 0;
+	for (i = 0; i < h->size; i++) {
+		cur = h->htable[i];
+		if (cur) {
+			slots_used++;
+			chain_len = 0;
+			while (cur) {
+				chain_len++;
+				cur = cur->next;
+			}
+
+			if (chain_len > max_chain_len)
+				max_chain_len = chain_len;
+		}
+	}
+
+	printf
+	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
+	     tag, h->nel, slots_used, h->size, max_chain_len);
+}
diff --git a/libsepol/src/hierarchy.c b/libsepol/src/hierarchy.c
new file mode 100644
index 0000000..778541a
--- /dev/null
+++ b/libsepol/src/hierarchy.c
@@ -0,0 +1,702 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * 	    Jason Tang <jtang@tresys.com>
+ *
+ * Updates: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *          adds checks based on newer boundary facility.
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * Copyright (c) 2008 NEC Corporation
+ *
+ *  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 <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+
+#define BOUNDS_AVTAB_SIZE 1024
+
+static int bounds_insert_helper(sepol_handle_t *handle, avtab_t *avtab,
+				avtab_key_t *avtab_key, avtab_datum_t *datum)
+{
+	int rc = avtab_insert(avtab, avtab_key, datum);
+	if (rc) {
+		if (rc == SEPOL_ENOMEM)
+			ERR(handle, "Insufficient memory");
+		else
+			ERR(handle, "Unexpected error (%d)", rc);
+	}
+	return rc;
+}
+
+
+static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
+			      avtab_t *global, avtab_t *other,
+			      avtab_key_t *avtab_key, avtab_datum_t *datum)
+{
+	int rc = 0;
+	avtab_datum_t *dup = avtab_search(avtab, avtab_key);
+
+	if (!dup) {
+		rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
+		if (rc) goto exit;
+	} else {
+		dup->data |= datum->data;
+	}
+
+	if (other) {
+		/* Search the other conditional avtab for the key and
+		 * add any common permissions to the global avtab
+		 */
+		uint32_t data = 0;
+		dup = avtab_search(other, avtab_key);
+		if (dup) {
+			data = dup->data & datum->data;
+			if (data) {
+				dup = avtab_search(global, avtab_key);
+				if (!dup) {
+					avtab_datum_t d;
+					d.data = data;
+					rc = bounds_insert_helper(handle, global,
+								  avtab_key, &d);
+					if (rc) goto exit;
+				} else {
+					dup->data |= data;
+				}
+			}
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
+			      avtab_t *avtab, avtab_t *global, avtab_t *other,
+			      uint32_t parent, uint32_t src, uint32_t tgt,
+			      uint32_t class, uint32_t data)
+{
+	int rc = 0;
+	avtab_key_t avtab_key;
+	avtab_datum_t datum;
+	ebitmap_node_t *tnode;
+	unsigned int i;
+
+	avtab_key.specified = AVTAB_ALLOWED;
+	avtab_key.target_class = class;
+	datum.data = data;
+
+	if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
+		avtab_key.source_type = parent;
+		ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
+			if (!ebitmap_node_get_bit(tnode, i))
+				continue;
+			avtab_key.target_type = i + 1;
+			rc = bounds_insert_rule(handle, avtab, global, other,
+						&avtab_key, &datum);
+			if (rc) goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
+				    cond_av_list_t *cur, avtab_t *avtab,
+				    avtab_t *global, avtab_t *other,
+				    uint32_t parent)
+{
+	int rc = 0;
+
+	for (; cur; cur = cur->next) {
+		avtab_ptr_t n = cur->node;
+		rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
+					n->key.source_type, n->key.target_type,
+					n->key.target_class, n->datum.data);
+		if (rc) goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+struct bounds_expand_args {
+	sepol_handle_t *handle;
+	policydb_t *p;
+	avtab_t *avtab;
+	uint32_t parent;
+};
+
+static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
+				       void *args)
+{
+	struct bounds_expand_args *a = (struct bounds_expand_args *)args;
+
+	if (!(k->specified & AVTAB_ALLOWED))
+		return 0;
+
+	return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
+				  a->parent, k->source_type, k->target_type,
+				  k->target_class, d->data);
+}
+
+struct bounds_cond_info {
+	avtab_t true_avtab;
+	avtab_t false_avtab;
+	cond_list_t *cond_list;
+	struct bounds_cond_info *next;
+};
+
+static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
+{
+	struct bounds_cond_info *next;
+
+	for (; cur; cur = next) {
+		next = cur->next;
+		avtab_destroy(&cur->true_avtab);
+		avtab_destroy(&cur->false_avtab);
+		cur->next = NULL;
+		free(cur);
+	}
+}
+
+static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
+				      avtab_t *global_avtab,
+				      struct bounds_cond_info **cond_info,
+				      uint32_t parent)
+{
+	int rc = 0;
+	struct bounds_expand_args args;
+	cond_list_t *cur;
+
+	avtab_init(global_avtab);
+	rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
+	if (rc) goto oom;
+
+	args.handle = handle;
+	args.p = p;
+	args.avtab = global_avtab;
+	args.parent = parent;
+	rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
+	if (rc) goto exit;
+
+	*cond_info = NULL;
+	for (cur = p->cond_list; cur; cur = cur->next) {
+		struct bounds_cond_info *ci;
+		ci = malloc(sizeof(struct bounds_cond_info));
+		if (!ci) goto oom;
+		avtab_init(&ci->true_avtab);
+		avtab_init(&ci->false_avtab);
+		ci->cond_list = cur;
+		ci->next = *cond_info;
+		*cond_info = ci;
+		if (cur->true_list) {
+			rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
+			if (rc) goto oom;
+			rc = bounds_expand_cond_rules(handle, p, cur->true_list,
+						      &ci->true_avtab, NULL,
+						      NULL, parent);
+			if (rc) goto exit;
+		}
+		if (cur->false_list) {
+			rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
+			if (rc) goto oom;
+			rc = bounds_expand_cond_rules(handle, p, cur->false_list,
+						      &ci->false_avtab,
+						      global_avtab,
+						      &ci->true_avtab, parent);
+			if (rc) goto exit;
+		}
+	}
+
+	return 0;
+
+oom:
+	ERR(handle, "Insufficient memory");
+
+exit:
+	ERR(handle,"Failed to expand parent rules\n");
+	avtab_destroy(global_avtab);
+	bounds_destroy_cond_info(*cond_info);
+	*cond_info = NULL;
+	return rc;
+}
+
+static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
+			      avtab_key_t *avtab_key, uint32_t data)
+{
+	avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
+	if (datum)
+		data &= ~datum->data;
+	if (global_avtab && data) {
+		datum = avtab_search(global_avtab, avtab_key);
+		if (datum)
+			data &= ~datum->data;
+	}
+
+	return data;
+}
+
+static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
+			  uint32_t class, uint32_t data, avtab_ptr_t *bad)
+{
+	struct avtab_node *new = malloc(sizeof(struct avtab_node));
+	if (new == NULL) {
+		ERR(handle, "Insufficient memory");
+		return SEPOL_ENOMEM;
+	}
+	memset(new, 0, sizeof(struct avtab_node));
+	new->key.source_type = src;
+	new->key.target_type = tgt;
+	new->key.target_class = class;
+	new->datum.data = data;
+	new->next = *bad;
+	*bad = new;
+
+	return 0;
+}
+
+static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
+			     avtab_t *global_avtab, avtab_t *cur_avtab,
+			     uint32_t child, uint32_t parent, uint32_t src,
+			     uint32_t tgt, uint32_t class, uint32_t data,
+			     avtab_ptr_t *bad, int *numbad)
+{
+	int rc = 0;
+	avtab_key_t avtab_key;
+	type_datum_t *td;
+	ebitmap_node_t *tnode;
+	unsigned int i;
+	uint32_t d;
+
+	avtab_key.specified = AVTAB_ALLOWED;
+	avtab_key.target_class = class;
+
+	if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
+		avtab_key.source_type = parent;
+		ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
+			if (!ebitmap_node_get_bit(tnode, i))
+				continue;
+			td = p->type_val_to_struct[i];
+			if (td && td->bounds) {
+				avtab_key.target_type = td->bounds;
+				d = bounds_not_covered(global_avtab, cur_avtab,
+						       &avtab_key, data);
+			} else {
+				avtab_key.target_type = i + 1;
+				d = bounds_not_covered(global_avtab, cur_avtab,
+						       &avtab_key, data);
+			}
+			if (d) {
+				(*numbad)++;
+				rc = bounds_add_bad(handle, child, i+1, class, d, bad);
+				if (rc) goto exit;
+			}
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
+				   avtab_t *global_avtab, avtab_t *cond_avtab,
+				   cond_av_list_t *rules, uint32_t child,
+				   uint32_t parent, avtab_ptr_t *bad,
+				   int *numbad)
+{
+	int rc = 0;
+	cond_av_list_t *cur;
+
+	for (cur = rules; cur; cur = cur->next) {
+		avtab_ptr_t ap = cur->node;
+		avtab_key_t *key = &ap->key;
+		avtab_datum_t *datum = &ap->datum;
+		if (!(key->specified & AVTAB_ALLOWED))
+			continue;
+		rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
+				       child, parent, key->source_type,
+				       key->target_type, key->target_class,
+				       datum->data, bad, numbad);
+		if (rc) goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+struct bounds_check_args {
+	sepol_handle_t *handle;
+	policydb_t *p;
+	avtab_t *cur_avtab;
+	uint32_t child;
+	uint32_t parent;
+	avtab_ptr_t bad;
+	int numbad;
+};
+
+static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
+				      void *args)
+{
+	struct bounds_check_args *a = (struct bounds_check_args *)args;
+
+	if (!(k->specified & AVTAB_ALLOWED))
+		return 0;
+
+	return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
+				 a->parent, k->source_type, k->target_type,
+				 k->target_class, d->data, &a->bad, &a->numbad);
+}
+
+static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
+				    avtab_t *global_avtab,
+				    struct bounds_cond_info *cond_info,
+				    uint32_t child, uint32_t parent,
+				    avtab_ptr_t *bad, int *numbad)
+{
+	int rc;
+	struct bounds_check_args args;
+	struct bounds_cond_info *cur;
+
+	args.handle = handle;
+	args.p = p;
+	args.cur_avtab = global_avtab;
+	args.child = child;
+	args.parent = parent;
+	args.bad = NULL;
+	args.numbad = 0;
+	rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
+	if (rc) goto exit;
+
+	for (cur = cond_info; cur; cur = cur->next) {
+		cond_list_t *node = cur->cond_list;
+		rc = bounds_check_cond_rules(handle, p, global_avtab,
+					     &cur->true_avtab,
+					     node->true_list, child, parent,
+					     &args.bad, &args.numbad);
+		if (rc) goto exit;
+
+		rc = bounds_check_cond_rules(handle, p, global_avtab,
+					     &cur->false_avtab,
+					     node->false_list, child, parent,
+					     &args.bad, &args.numbad);
+		if (rc) goto exit;
+	}
+
+	*numbad += args.numbad;
+	*bad = args.bad;
+
+exit:
+	return rc;
+}
+
+int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+		      uint32_t parent, avtab_ptr_t *bad, int *numbad)
+{
+	int rc = 0;
+	avtab_t global_avtab;
+	struct bounds_cond_info *cond_info = NULL;
+
+	rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
+	if (rc) goto exit;
+
+	rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
+				      child, parent, bad, numbad);
+
+	bounds_destroy_cond_info(cond_info);
+	avtab_destroy(&global_avtab);
+
+exit:
+	return rc;
+}
+
+struct bounds_args {
+	sepol_handle_t *handle;
+	policydb_t *p;
+	int numbad;
+};
+
+static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+			  uint32_t parent, avtab_ptr_t cur)
+{
+	ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
+	    p->p_type_val_to_name[child - 1],
+	    p->p_type_val_to_name[parent - 1]);
+	for (; cur; cur = cur->next) {
+		ERR(handle, "    %s %s : %s { %s }",
+		    p->p_type_val_to_name[cur->key.source_type - 1],
+		    p->p_type_val_to_name[cur->key.target_type - 1],
+		    p->p_class_val_to_name[cur->key.target_class - 1],
+		    sepol_av_to_string(p, cur->key.target_class,
+				       cur->datum.data));
+	}
+}
+
+void bounds_destroy_bad(avtab_ptr_t cur)
+{
+	avtab_ptr_t next;
+
+	for (; cur; cur = next) {
+		next = cur->next;
+		cur->next = NULL;
+		free(cur);
+	}
+}
+
+static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
+				      hashtab_datum_t d, void *args)
+{
+	int rc = 0;
+	struct bounds_args *a = (struct bounds_args *)args;
+	type_datum_t *t = (type_datum_t *)d;
+	avtab_ptr_t bad = NULL;
+
+	if (t->bounds) {
+		rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
+				       &bad, &a->numbad);
+		if (bad) {
+			bounds_report(a->handle, a->p, t->s.value, t->bounds,
+				      bad);
+			bounds_destroy_bad(bad);
+		}
+	}
+
+	return rc;
+}
+
+int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
+{
+	int rc;
+	struct bounds_args args;
+
+	args.handle = handle;
+	args.p = p;
+	args.numbad = 0;
+
+	rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
+	if (rc) goto exit;
+
+	if (args.numbad > 0) {
+		ERR(handle, "%d errors found during type bounds check",
+		    args.numbad);
+		rc = SEPOL_ERR;
+	}
+
+exit:
+	return rc;
+}
+
+/* The role bounds is defined as: a child role cannot have a type that
+ * its parent doesn't have.
+ */
+static int bounds_check_role_callback(hashtab_key_t k,
+				      hashtab_datum_t d, void *args)
+{
+	struct bounds_args *a = (struct bounds_args *)args;
+	role_datum_t *r = (role_datum_t *) d;
+	role_datum_t *rp = NULL;
+
+	if (!r->bounds)
+		return 0;
+
+	rp = a->p->role_val_to_struct[r->bounds - 1];
+
+	if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
+		ERR(a->handle, "Role bounds violation, %s exceeds %s",
+		    (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
+		a->numbad++;
+	}
+
+	return 0;
+}
+
+int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
+{
+	struct bounds_args args;
+
+	args.handle = handle;
+	args.p = p;
+	args.numbad = 0;
+
+	hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
+
+	if (args.numbad > 0) {
+		ERR(handle, "%d errors found during role bounds check",
+		    args.numbad);
+		return SEPOL_ERR;
+	}
+
+	return 0;
+}
+
+/* The user bounds is defined as: a child user cannot have a role that
+ * its parent doesn't have.
+ */
+static int bounds_check_user_callback(hashtab_key_t k,
+				      hashtab_datum_t d, void *args)
+{
+	struct bounds_args *a = (struct bounds_args *)args;
+	user_datum_t *u = (user_datum_t *) d;
+	user_datum_t *up = NULL;
+
+	if (!u->bounds)
+		return 0;
+
+	up = a->p->user_val_to_struct[u->bounds - 1];
+
+	if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
+		ERR(a->handle, "User bounds violation, %s exceeds %s",
+		    (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
+		a->numbad++;
+	}
+
+	return 0;
+}
+
+int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
+{
+	struct bounds_args args;
+
+	args.handle = handle;
+	args.p = p;
+	args.numbad = 0;
+
+	hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
+
+	if (args.numbad > 0) {
+		ERR(handle, "%d errors found during user bounds check",
+		    args.numbad);
+		return SEPOL_ERR;
+	}
+
+	return 0;
+}
+
+#define add_hierarchy_callback_template(prefix)				\
+	int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
+					    hashtab_datum_t d, void *args) \
+{								\
+	struct bounds_args *a = (struct bounds_args *)args;		\
+	sepol_handle_t *handle = a->handle;				\
+	policydb_t *p = a->p;						\
+	prefix##_datum_t *datum = (prefix##_datum_t *)d;		\
+	prefix##_datum_t *parent;					\
+	char *parent_name, *datum_name, *tmp;				\
+									\
+	if (!datum->bounds) {						\
+		datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
+									\
+		tmp = strrchr(datum_name, '.');				\
+		/* no '.' means it has no parent */			\
+		if (!tmp) return 0;					\
+									\
+		parent_name = strdup(datum_name);			\
+		if (!parent_name) {					\
+			ERR(handle, "Insufficient memory");		\
+			return SEPOL_ENOMEM;				\
+		}							\
+		parent_name[tmp - datum_name] = '\0';			\
+									\
+		parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
+		if (!parent) {						\
+			/* Orphan type/role/user */			\
+			ERR(handle, "%s doesn't exist, %s is an orphan",\
+			    parent_name,				\
+			    p->p_##prefix##_val_to_name[datum->s.value - 1]); \
+			free(parent_name);				\
+			a->numbad++;					\
+			return 0;					\
+		}							\
+		datum->bounds = parent->s.value;			\
+		free(parent_name);					\
+	}								\
+									\
+	return 0;							\
+}								\
+
+static add_hierarchy_callback_template(type)
+static add_hierarchy_callback_template(role)
+static add_hierarchy_callback_template(user)
+
+int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
+{
+	int rc = 0;
+	struct bounds_args args;
+
+	args.handle = handle;
+	args.p = p;
+	args.numbad = 0;
+
+	rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
+	if (rc) goto exit;
+
+	rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
+	if (rc) goto exit;
+
+	rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
+	if (rc) goto exit;
+
+	if (args.numbad > 0) {
+		ERR(handle, "%d errors found while adding hierarchies",
+		    args.numbad);
+		rc = SEPOL_ERR;
+	}
+
+exit:
+	return rc;
+}
+
+int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
+{
+	int rc = 0;
+	int violation = 0;
+
+	rc = hierarchy_add_bounds(handle, p);
+	if (rc) goto exit;
+
+	rc = bounds_check_users(handle, p);
+	if (rc)
+		violation = 1;
+
+	rc = bounds_check_roles(handle, p);
+	if (rc)
+		violation = 1;
+
+	rc = bounds_check_types(handle, p);
+	if (rc) {
+		if (rc == SEPOL_ERR)
+			violation = 1;
+		else
+			goto exit;
+	}
+
+	if (violation)
+		rc = SEPOL_ERR;
+
+exit:
+	return rc;
+}
diff --git a/libsepol/src/iface_internal.h b/libsepol/src/iface_internal.h
new file mode 100644
index 0000000..5b78d9b
--- /dev/null
+++ b/libsepol/src/iface_internal.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_IFACE_INTERNAL_H_
+#define _SEPOL_IFACE_INTERNAL_H_
+
+#include <sepol/iface_record.h>
+#include <sepol/interfaces.h>
+#include "dso.h"
+
+hidden_proto(sepol_iface_create)
+    hidden_proto(sepol_iface_free)
+    hidden_proto(sepol_iface_get_ifcon)
+    hidden_proto(sepol_iface_get_msgcon)
+    hidden_proto(sepol_iface_get_name)
+    hidden_proto(sepol_iface_key_create)
+    hidden_proto(sepol_iface_key_unpack)
+    hidden_proto(sepol_iface_set_ifcon)
+    hidden_proto(sepol_iface_set_msgcon)
+    hidden_proto(sepol_iface_set_name)
+#endif
diff --git a/libsepol/src/iface_record.c b/libsepol/src/iface_record.c
new file mode 100644
index 0000000..09adeb7
--- /dev/null
+++ b/libsepol/src/iface_record.c
@@ -0,0 +1,233 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "iface_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_iface {
+
+	/* Interface name */
+	char *name;
+
+	/* Interface context */
+	sepol_context_t *netif_con;
+
+	/* Message context */
+	sepol_context_t *netmsg_con;
+};
+
+struct sepol_iface_key {
+
+	/* Interface name */
+	const char *name;
+};
+
+/* Key */
+int sepol_iface_key_create(sepol_handle_t * handle,
+			   const char *name, sepol_iface_key_t ** key_ptr)
+{
+
+	sepol_iface_key_t *tmp_key =
+	    (sepol_iface_key_t *) malloc(sizeof(sepol_iface_key_t));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, could not create interface key");
+		return STATUS_ERR;
+	}
+
+	tmp_key->name = name;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_key_create)
+
+void sepol_iface_key_unpack(const sepol_iface_key_t * key, const char **name)
+{
+
+	*name = key->name;
+}
+
+hidden_def(sepol_iface_key_unpack)
+
+int sepol_iface_key_extract(sepol_handle_t * handle,
+			    const sepol_iface_t * iface,
+			    sepol_iface_key_t ** key_ptr)
+{
+
+	if (sepol_iface_key_create(handle, iface->name, key_ptr) < 0) {
+		ERR(handle, "could not extract key from "
+		    "interface %s", iface->name);
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_iface_key_free(sepol_iface_key_t * key)
+{
+	free(key);
+}
+
+int sepol_iface_compare(const sepol_iface_t * iface,
+			const sepol_iface_key_t * key)
+{
+
+	return strcmp(iface->name, key->name);
+}
+
+int sepol_iface_compare2(const sepol_iface_t * iface,
+			 const sepol_iface_t * iface2)
+{
+
+	return strcmp(iface->name, iface2->name);
+}
+
+/* Create */
+int sepol_iface_create(sepol_handle_t * handle, sepol_iface_t ** iface)
+{
+
+	sepol_iface_t *tmp_iface =
+	    (sepol_iface_t *) malloc(sizeof(sepol_iface_t));
+
+	if (!tmp_iface) {
+		ERR(handle, "out of memory, could not create "
+		    "interface record");
+		return STATUS_ERR;
+	}
+
+	tmp_iface->name = NULL;
+	tmp_iface->netif_con = NULL;
+	tmp_iface->netmsg_con = NULL;
+	*iface = tmp_iface;
+
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_create)
+
+/* Name */
+const char *sepol_iface_get_name(const sepol_iface_t * iface)
+{
+
+	return iface->name;
+}
+
+hidden_def(sepol_iface_get_name)
+
+int sepol_iface_set_name(sepol_handle_t * handle,
+			 sepol_iface_t * iface, const char *name)
+{
+
+	char *tmp_name = strdup(name);
+	if (!tmp_name) {
+		ERR(handle, "out of memory, " "could not set interface name");
+		return STATUS_ERR;
+	}
+	free(iface->name);
+	iface->name = tmp_name;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_name)
+
+/* Interface Context */
+sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface)
+{
+
+	return iface->netif_con;
+}
+
+hidden_def(sepol_iface_get_ifcon)
+
+int sepol_iface_set_ifcon(sepol_handle_t * handle,
+			  sepol_iface_t * iface, sepol_context_t * con)
+{
+
+	sepol_context_t *newcon;
+
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set interface context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(iface->netif_con);
+	iface->netif_con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_ifcon)
+
+/* Message Context */
+sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface)
+{
+
+	return iface->netmsg_con;
+}
+
+hidden_def(sepol_iface_get_msgcon)
+
+int sepol_iface_set_msgcon(sepol_handle_t * handle,
+			   sepol_iface_t * iface, sepol_context_t * con)
+{
+
+	sepol_context_t *newcon;
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set message context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(iface->netmsg_con);
+	iface->netmsg_con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_msgcon)
+
+/* Deep copy clone */
+int sepol_iface_clone(sepol_handle_t * handle,
+		      const sepol_iface_t * iface, sepol_iface_t ** iface_ptr)
+{
+
+	sepol_iface_t *new_iface = NULL;
+	if (sepol_iface_create(handle, &new_iface) < 0)
+		goto err;
+
+	if (sepol_iface_set_name(handle, new_iface, iface->name) < 0)
+		goto err;
+
+	if (iface->netif_con &&
+	    (sepol_context_clone
+	     (handle, iface->netif_con, &new_iface->netif_con) < 0))
+		goto err;
+
+	if (iface->netmsg_con &&
+	    (sepol_context_clone
+	     (handle, iface->netmsg_con, &new_iface->netmsg_con) < 0))
+		goto err;
+
+	*iface_ptr = new_iface;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not clone interface record");
+	sepol_iface_free(new_iface);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_iface_free(sepol_iface_t * iface)
+{
+
+	if (!iface)
+		return;
+
+	free(iface->name);
+	sepol_context_free(iface->netif_con);
+	sepol_context_free(iface->netmsg_con);
+	free(iface);
+}
+
+hidden_def(sepol_iface_free)
diff --git a/libsepol/src/interfaces.c b/libsepol/src/interfaces.c
new file mode 100644
index 0000000..f371d0b
--- /dev/null
+++ b/libsepol/src/interfaces.c
@@ -0,0 +1,271 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/interfaces.h>
+#include "iface_internal.h"
+
+/* Create a low level structure from record */
+static int iface_from_record(sepol_handle_t * handle,
+			     const policydb_t * policydb,
+			     ocontext_t ** iface, const sepol_iface_t * record)
+{
+
+	ocontext_t *tmp_iface = NULL;
+	context_struct_t *tmp_con = NULL;
+
+	tmp_iface = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+	if (!tmp_iface)
+		goto omem;
+
+	/* Name */
+	tmp_iface->u.name = strdup(sepol_iface_get_name(record));
+	if (!tmp_iface->u.name)
+		goto omem;
+
+	/* Interface Context */
+	if (context_from_record(handle, policydb,
+				&tmp_con, sepol_iface_get_ifcon(record)) < 0)
+		goto err;
+	context_cpy(&tmp_iface->context[0], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	/* Message Context */
+	if (context_from_record(handle, policydb,
+				&tmp_con, sepol_iface_get_msgcon(record)) < 0)
+		goto err;
+	context_cpy(&tmp_iface->context[1], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	*iface = tmp_iface;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	if (tmp_iface != NULL) {
+		free(tmp_iface->u.name);
+		context_destroy(&tmp_iface->context[0]);
+		context_destroy(&tmp_iface->context[1]);
+		free(tmp_iface);
+	}
+	context_destroy(tmp_con);
+	free(tmp_con);
+	ERR(handle, "error creating interface structure");
+	return STATUS_ERR;
+}
+
+static int iface_to_record(sepol_handle_t * handle,
+			   const policydb_t * policydb,
+			   ocontext_t * iface, sepol_iface_t ** record)
+{
+
+	char *name = iface->u.name;
+	context_struct_t *ifcon = &iface->context[0];
+	context_struct_t *msgcon = &iface->context[1];
+
+	sepol_context_t *tmp_con = NULL;
+	sepol_iface_t *tmp_record = NULL;
+
+	if (sepol_iface_create(handle, &tmp_record) < 0)
+		goto err;
+
+	if (sepol_iface_set_name(handle, tmp_record, name) < 0)
+		goto err;
+
+	if (context_to_record(handle, policydb, ifcon, &tmp_con) < 0)
+		goto err;
+	if (sepol_iface_set_ifcon(handle, tmp_record, tmp_con) < 0)
+		goto err;
+	sepol_context_free(tmp_con);
+	tmp_con = NULL;
+
+	if (context_to_record(handle, policydb, msgcon, &tmp_con) < 0)
+		goto err;
+	if (sepol_iface_set_msgcon(handle, tmp_record, tmp_con) < 0)
+		goto err;
+	sepol_context_free(tmp_con);
+	tmp_con = NULL;
+
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not convert interface %s to record", name);
+	sepol_context_free(tmp_con);
+	sepol_iface_free(tmp_record);
+	return STATUS_ERR;
+}
+
+/* Check if an interface exists */
+int sepol_iface_exists(sepol_handle_t * handle __attribute__ ((unused)),
+		       const sepol_policydb_t * p,
+		       const sepol_iface_key_t * key, int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	const char *name;
+	sepol_iface_key_unpack(key, &name);
+
+	head = policydb->ocontexts[OCON_NETIF];
+	for (c = head; c; c = c->next) {
+		if (!strcmp(name, c->u.name)) {
+			*response = 1;
+			return STATUS_SUCCESS;
+		}
+	}
+	*response = 0;
+
+	return STATUS_SUCCESS;
+}
+
+/* Query an interface */
+int sepol_iface_query(sepol_handle_t * handle,
+		      const sepol_policydb_t * p,
+		      const sepol_iface_key_t * key, sepol_iface_t ** response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	const char *name;
+	sepol_iface_key_unpack(key, &name);
+
+	head = policydb->ocontexts[OCON_NETIF];
+	for (c = head; c; c = c->next) {
+		if (!strcmp(name, c->u.name)) {
+
+			if (iface_to_record(handle, policydb, c, response) < 0)
+				goto err;
+
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = NULL;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not query interface %s", name);
+	return STATUS_ERR;
+}
+
+/* Load an interface into policy */
+int sepol_iface_modify(sepol_handle_t * handle,
+		       sepol_policydb_t * p,
+		       const sepol_iface_key_t * key,
+		       const sepol_iface_t * data)
+{
+
+	policydb_t *policydb = &p->p;
+	ocontext_t *head, *prev, *c, *iface = NULL;
+
+	const char *name;
+	sepol_iface_key_unpack(key, &name);
+
+	if (iface_from_record(handle, policydb, &iface, data) < 0)
+		goto err;
+
+	prev = NULL;
+	head = policydb->ocontexts[OCON_NETIF];
+	for (c = head; c; c = c->next) {
+		if (!strcmp(name, c->u.name)) {
+
+			/* Replace */
+			iface->next = c->next;
+			if (prev == NULL)
+				policydb->ocontexts[OCON_NETIF] = iface;
+			else
+				prev->next = iface;
+			free(c->u.name);
+			context_destroy(&c->context[0]);
+			context_destroy(&c->context[1]);
+			free(c);
+
+			return STATUS_SUCCESS;
+		}
+		prev = c;
+	}
+
+	/* Attach to context list */
+	iface->next = policydb->ocontexts[OCON_NETIF];
+	policydb->ocontexts[OCON_NETIF] = iface;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "error while loading interface %s", name);
+
+	if (iface != NULL) {
+		free(iface->u.name);
+		context_destroy(&iface->context[0]);
+		context_destroy(&iface->context[1]);
+		free(iface);
+	}
+	return STATUS_ERR;
+}
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle __attribute__ ((unused)),
+			     const sepol_policydb_t * p, unsigned int *response)
+{
+
+	unsigned int count = 0;
+	ocontext_t *c, *head;
+	const policydb_t *policydb = &p->p;
+
+	head = policydb->ocontexts[OCON_NETIF];
+	for (c = head; c != NULL; c = c->next)
+		count++;
+
+	*response = count;
+
+	return STATUS_SUCCESS;
+}
+
+int sepol_iface_iterate(sepol_handle_t * handle,
+			const sepol_policydb_t * p,
+			int (*fn) (const sepol_iface_t * iface,
+				   void *fn_arg), void *arg)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	sepol_iface_t *iface = NULL;
+
+	head = policydb->ocontexts[OCON_NETIF];
+	for (c = head; c; c = c->next) {
+		int status;
+
+		if (iface_to_record(handle, policydb, c, &iface) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(iface, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_iface_free(iface);
+		iface = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not iterate over interfaces");
+	sepol_iface_free(iface);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
new file mode 100644
index 0000000..0a46b09
--- /dev/null
+++ b/libsepol/src/libsepol.map.in
@@ -0,0 +1,52 @@
+LIBSEPOL_1.0 {
+  global: 
+	expand_module_avrules;
+	sepol_module_package_*; sepol_link_modules; sepol_expand_module; sepol_link_packages;
+	sepol_bool_*; sepol_genbools*; 
+	sepol_context_*; sepol_mls_*; sepol_check_context;
+	sepol_iface_*; 
+	sepol_port_*;
+	sepol_node_*;
+	sepol_user_*; sepol_genusers; sepol_set_delusers;
+	sepol_msg_*; sepol_debug;
+	sepol_handle_*;
+	sepol_policydb_*; sepol_set_policydb_from_file; 
+	sepol_policy_kern_*;
+	sepol_policy_file_*;
+	sepol_get_disable_dontaudit;
+	sepol_set_disable_dontaudit;
+	sepol_set_expand_consume_base;
+	sepol_get_preserve_tunables; sepol_set_preserve_tunables;
+	cil_db_init;
+	cil_set_disable_dontaudit;
+	cil_set_disable_neverallow;
+	cil_set_preserve_tunables;
+	cil_set_handle_unknown;
+	cil_db_destroy;
+	cil_add_file;
+	cil_compile;
+	cil_build_policydb;
+	cil_userprefixes_to_string;
+	cil_selinuxusers_to_string;
+	cil_filecons_to_string;
+	cil_set_log_level;
+	cil_set_log_handler;
+	cil_set_malloc_error_handler;
+  local: *;
+};
+
+LIBSEPOL_1.1 {
+  global:
+	cil_build_policydb;
+	cil_compile;
+	cil_userprefixes_to_string;
+	cil_selinuxusers_to_string;
+	cil_filecons_to_string;
+	cil_set_target_platform;
+	cil_set_policy_version;
+	cil_set_mls;
+	sepol_ppfile_to_module_package;
+	sepol_module_package_to_cil;
+	sepol_module_policydb_to_cil;
+  local: *;
+} LIBSEPOL_1.0;
diff --git a/libsepol/src/libsepol.pc.in b/libsepol/src/libsepol.pc.in
new file mode 100644
index 0000000..e52f589
--- /dev/null
+++ b/libsepol/src/libsepol.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@libdir@
+includedir=@includedir@
+
+Name: libsepol
+Description: SELinux policy library
+Version: @VERSION@
+URL: http://userspace.selinuxproject.org/
+Libs: -L${libdir} -lsepol
+Cflags: -I${includedir}
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
new file mode 100644
index 0000000..f211164
--- /dev/null
+++ b/libsepol/src/link.c
@@ -0,0 +1,2668 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *	    Joshua Brindle <jbrindle@tresys.com>
+ *          Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ *  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 <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/util.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+typedef struct policy_module {
+	policydb_t *policy;
+	uint32_t num_decls;
+	uint32_t *map[SYM_NUM];
+	uint32_t *avdecl_map;
+	uint32_t **perm_map;
+	uint32_t *perm_map_len;
+
+	/* a pointer to within the base module's avrule_block chain to
+	 * where this module's global now resides */
+	avrule_block_t *base_global;
+} policy_module_t;
+
+typedef struct link_state {
+	int verbose;
+	policydb_t *base;
+	avrule_block_t *last_avrule_block, *last_base_avrule_block;
+	uint32_t next_decl_id, current_decl_id;
+
+	/* temporary variables, used during hashtab_map() calls */
+	policy_module_t *cur;
+	char *cur_mod_name;
+	avrule_decl_t *dest_decl;
+	class_datum_t *src_class, *dest_class;
+	char *dest_class_name;
+	char dest_class_req;	/* flag indicating the class was not declared */
+	uint32_t symbol_num;
+	/* used to report the name of the module if dependancy error occurs */
+	policydb_t **decl_to_mod;
+
+	/* error reporting fields */
+	sepol_handle_t *handle;
+} link_state_t;
+
+typedef struct missing_requirement {
+	uint32_t symbol_type;
+	uint32_t symbol_value;
+	uint32_t perm_value;
+} missing_requirement_t;
+
+static const char *symtab_names[SYM_NUM] = {
+	"common", "class", "role", "type/attribute", "user",
+	"bool", "level", "category"
+};
+
+/* Deallocates all elements within a module, but NOT the policydb_t
+ * structure within, as well as the pointer itself. */
+static void policy_module_destroy(policy_module_t * mod)
+{
+	unsigned int i;
+	if (mod == NULL) {
+		return;
+	}
+	for (i = 0; i < SYM_NUM; i++) {
+		free(mod->map[i]);
+	}
+	for (i = 0; mod->perm_map != NULL && i < mod->policy->p_classes.nprim;
+	     i++) {
+		free(mod->perm_map[i]);
+	}
+	free(mod->perm_map);
+	free(mod->perm_map_len);
+	free(mod->avdecl_map);
+	free(mod);
+}
+
+/***** functions that copy identifiers from a module to base *****/
+
+/* Note: there is currently no scoping for permissions, which causes some
+ * strange side-effects. The current approach is this:
+ *
+ * a) perm is required and the class _and_ perm are declared in base: only add a mapping.
+ * b) perm is required and the class and perm are _not_ declared in base: simply add the permissions
+ *    to the object class. This means that the requirements for the decl are the union of the permissions
+ *    required for all decls, but who cares.
+ * c) perm is required, the class is declared in base, but the perm is not present. Nothing we can do
+ *    here because we can't mark a single permission as required, so we bail with a requirement error
+ *    _even_ if we are in an optional.
+ *
+ * A is correct behavior, b is wrong but not too bad, c is totall wrong for optionals. Fixing this requires
+ * a format change.
+ */
+static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+				    void *data)
+{
+	char *perm_id = key, *new_id = NULL;
+	perm_datum_t *perm, *new_perm = NULL, *dest_perm;
+	link_state_t *state = (link_state_t *) data;
+
+	class_datum_t *src_class = state->src_class;
+	class_datum_t *dest_class = state->dest_class;
+	policy_module_t *mod = state->cur;
+	uint32_t sclassi = src_class->s.value - 1;
+	int ret;
+
+	perm = (perm_datum_t *) datum;
+	dest_perm = hashtab_search(dest_class->permissions.table, perm_id);
+	if (dest_perm == NULL && dest_class->comdatum != NULL) {
+		dest_perm =
+		    hashtab_search(dest_class->comdatum->permissions.table,
+				   perm_id);
+	}
+
+	if (dest_perm == NULL) {
+		/* If the object class was not declared in the base, add the perm
+		 * to the object class. */
+		if (state->dest_class_req) {
+			/* If the class was required (not declared), insert the new permission */
+			new_id = strdup(perm_id);
+			if (new_id == NULL) {
+				ERR(state->handle, "Memory error");
+				ret = SEPOL_ERR;
+				goto err;
+			}
+			new_perm =
+			    (perm_datum_t *) calloc(1, sizeof(perm_datum_t));
+			if (new_perm == NULL) {
+				ERR(state->handle, "Memory error");
+				ret = SEPOL_ERR;
+				goto err;
+			}
+			ret = hashtab_insert(dest_class->permissions.table,
+					     (hashtab_key_t) new_id,
+					     (hashtab_datum_t) new_perm);
+			if (ret) {
+				ERR(state->handle,
+				    "could not insert permission into class\n");
+				goto err;
+			}
+			new_perm->s.value = dest_class->permissions.nprim + 1;
+			dest_perm = new_perm;
+		} else {
+			/* this is case c from above */
+			ERR(state->handle,
+			    "Module %s depends on permission %s in class %s, not satisfied",
+			    state->cur_mod_name, perm_id,
+			    state->dest_class_name);
+			return SEPOL_EREQ;
+		}
+	}
+
+	/* build the mapping for permissions encompassing this class.
+	 * unlike symbols, the permission map translates between
+	 * module permission bit to target permission bit.  that bit
+	 * may have originated from the class -or- it could be from
+	 * the class's common parent.*/
+	if (perm->s.value > mod->perm_map_len[sclassi]) {
+		uint32_t *newmap = calloc(perm->s.value, sizeof(*newmap));
+		if (newmap == NULL) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		memcpy(newmap, mod->perm_map[sclassi],
+		       mod->perm_map_len[sclassi] * sizeof(*newmap));
+		free(mod->perm_map[sclassi]);
+		mod->perm_map[sclassi] = newmap;
+		mod->perm_map_len[sclassi] = perm->s.value;
+	}
+	mod->perm_map[sclassi][perm->s.value - 1] = dest_perm->s.value;
+
+	return 0;
+      err:
+	free(new_id);
+	free(new_perm);
+	return ret;
+}
+
+static int class_copy_default_new_object(link_state_t *state,
+					 class_datum_t *olddatum,
+					 class_datum_t *newdatum)
+{
+	if (olddatum->default_user) {
+		if (newdatum->default_user && olddatum->default_user != newdatum->default_user) {
+			ERR(state->handle, "Found conflicting default user definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_user = olddatum->default_user;
+	}
+	if (olddatum->default_role) {
+		if (newdatum->default_role && olddatum->default_role != newdatum->default_role) {
+			ERR(state->handle, "Found conflicting default role definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_role = olddatum->default_role;
+	}
+	if (olddatum->default_type) {
+		if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
+			ERR(state->handle, "Found conflicting default type definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_type = olddatum->default_type;
+	}
+	if (olddatum->default_range) {
+		if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
+			ERR(state->handle, "Found conflicting default range definitions");
+			return SEPOL_ENOTSUP;
+		}
+		newdatum->default_range = olddatum->default_range;
+	}
+	return 0;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			       void *data)
+{
+	char *id = key, *new_id = NULL;
+	class_datum_t *cladatum, *new_class = NULL;
+	link_state_t *state = (link_state_t *) data;
+	scope_datum_t *scope = NULL;
+	int ret;
+
+	cladatum = (class_datum_t *) datum;
+	state->dest_class_req = 0;
+
+	new_class = hashtab_search(state->base->p_classes.table, id);
+	/* If there is not an object class already in the base symtab that means
+	 * that either a) a module is trying to declare a new object class (which
+	 * the compiler should prevent) or b) an object class was required that is
+	 * not in the base.
+	 */
+	if (new_class == NULL) {
+		scope =
+		    hashtab_search(state->cur->policy->p_classes_scope.table,
+				   id);
+		if (scope == NULL) {
+			ret = SEPOL_ERR;
+			goto err;
+		}
+		if (scope->scope == SCOPE_DECL) {
+			/* disallow declarations in modules */
+			ERR(state->handle,
+			    "%s: Modules may not yet declare new classes.",
+			    state->cur_mod_name);
+			ret = SEPOL_ENOTSUP;
+			goto err;
+		} else {
+			/* It would be nice to error early here because the requirement is
+			 * not met, but we cannot because the decl might be optional (in which
+			 * case we should record the requirement so that it is just turned
+			 * off). Note: this will break horribly if modules can declare object
+			 * classes because the class numbers will be all wrong (i.e., they
+			 * might be assigned in the order they were required rather than the
+			 * current scheme which ensures correct numbering by ordering the 
+			 * declarations properly). This can't be fixed until some infrastructure
+			 * for querying the object class numbers is in place. */
+			state->dest_class_req = 1;
+			new_class =
+			    (class_datum_t *) calloc(1, sizeof(class_datum_t));
+			if (new_class == NULL) {
+				ERR(state->handle, "Memory error\n");
+				ret = SEPOL_ERR;
+				goto err;
+			}
+			if (symtab_init
+			    (&new_class->permissions, PERM_SYMTAB_SIZE)) {
+				ret = SEPOL_ERR;
+				goto err;
+			}
+			new_id = strdup(id);
+			if (new_id == NULL) {
+				ERR(state->handle, "Memory error\n");
+				symtab_destroy(&new_class->permissions);
+				ret = SEPOL_ERR;
+				goto err;
+			}
+			ret = hashtab_insert(state->base->p_classes.table,
+					     (hashtab_key_t) new_id,
+					     (hashtab_datum_t) new_class);
+			if (ret) {
+				ERR(state->handle,
+				    "could not insert new class into symtab");
+				symtab_destroy(&new_class->permissions);
+				goto err;
+			}
+			new_class->s.value = ++(state->base->p_classes.nprim);
+		}
+	}
+
+	state->cur->map[SYM_CLASSES][cladatum->s.value - 1] =
+	    new_class->s.value;
+
+	/* copy permissions */
+	state->src_class = cladatum;
+	state->dest_class = new_class;
+	state->dest_class_name = (char *)key;
+
+	/* copy default new object rules */
+	ret = class_copy_default_new_object(state, cladatum, new_class);
+	if (ret)
+		return ret;
+
+	ret =
+	    hashtab_map(cladatum->permissions.table, permission_copy_callback,
+			state);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+      err:
+	free(new_class);
+	free(new_id);
+	return ret;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id = key, *new_id = NULL;
+	role_datum_t *role, *base_role, *new_role = NULL;
+	link_state_t *state = (link_state_t *) data;
+
+	role = (role_datum_t *) datum;
+
+	base_role = hashtab_search(state->base->p_roles.table, id);
+	if (base_role != NULL) {
+		/* role already exists.  check that it is what this
+		 * module expected.  duplicate declarations (e.g., two
+		 * modules both declare role foo_r) is checked during
+		 * scope_copy_callback(). */
+		if (role->flavor == ROLE_ATTRIB
+		    && base_role->flavor != ROLE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be a role attribute, but it was already declared as a regular role.",
+			    state->cur_mod_name, id);
+			return -1;
+		} else if (role->flavor != ROLE_ATTRIB
+			   && base_role->flavor == ROLE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be a regular role, but it was already declared as a role attribute.",
+			    state->cur_mod_name, id);
+			return -1;
+		}
+	} else {
+		if (state->verbose)
+			INFO(state->handle, "copying role %s", id);
+
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+
+		if ((new_role =
+		     (role_datum_t *) malloc(sizeof(*new_role))) == NULL) {
+			goto cleanup;
+		}
+		role_datum_init(new_role);
+
+		/* new_role's dominates, types and roles field will be copied
+		 * during role_fix_callback() */
+		new_role->flavor = role->flavor;
+		new_role->s.value = state->base->p_roles.nprim + 1;
+
+		ret = hashtab_insert(state->base->p_roles.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_role);
+		if (ret) {
+			goto cleanup;
+		}
+		state->base->p_roles.nprim++;
+		base_role = new_role;
+	}
+
+	if (state->dest_decl) {
+		new_id = NULL;
+		if ((new_role = malloc(sizeof(*new_role))) == NULL) {
+			goto cleanup;
+		}
+		role_datum_init(new_role);
+		new_role->flavor = base_role->flavor;
+		new_role->s.value = base_role->s.value;
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+		if (hashtab_insert
+		    (state->dest_decl->p_roles.table, new_id, new_role)) {
+			goto cleanup;
+		}
+		state->dest_decl->p_roles.nprim++;
+	}
+
+	state->cur->map[SYM_ROLES][role->s.value - 1] = base_role->s.value;
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	role_datum_destroy(new_role);
+	free(new_id);
+	free(new_role);
+	return -1;
+}
+
+/* Copy types and attributes from a module into the base module. The
+ * attributes are copied, but the types that make up this attribute
+ * are delayed type_fix_callback(). */
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id = key, *new_id = NULL;
+	type_datum_t *type, *base_type, *new_type = NULL;
+	link_state_t *state = (link_state_t *) data;
+
+	type = (type_datum_t *) datum;
+	if ((type->flavor == TYPE_TYPE && !type->primary)
+	    || type->flavor == TYPE_ALIAS) {
+		/* aliases are handled later, in alias_copy_callback() */
+		return 0;
+	}
+
+	base_type = hashtab_search(state->base->p_types.table, id);
+	if (base_type != NULL) {
+		/* type already exists.  check that it is what this
+		 * module expected.  duplicate declarations (e.g., two
+		 * modules both declare type foo_t) is checked during
+		 * scope_copy_callback(). */
+		if (type->flavor == TYPE_ATTRIB
+		    && base_type->flavor != TYPE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be an attribute, but it was already declared as a type.",
+			    state->cur_mod_name, id);
+			return -1;
+		} else if (type->flavor != TYPE_ATTRIB
+			   && base_type->flavor == TYPE_ATTRIB) {
+			ERR(state->handle,
+			    "%s: Expected %s to be a type, but it was already declared as an attribute.",
+			    state->cur_mod_name, id);
+			return -1;
+		}
+		/* permissive should pass to the base type */
+		base_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+	} else {
+		if (state->verbose)
+			INFO(state->handle, "copying type %s", id);
+
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+
+		if ((new_type =
+		     (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+			goto cleanup;
+		}
+		new_type->primary = type->primary;
+		new_type->flags = type->flags;
+		new_type->flavor = type->flavor;
+		/* for attributes, the writing of new_type->types is
+		   done in type_fix_callback() */
+
+		new_type->s.value = state->base->p_types.nprim + 1;
+
+		ret = hashtab_insert(state->base->p_types.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_type);
+		if (ret) {
+			goto cleanup;
+		}
+		state->base->p_types.nprim++;
+		base_type = new_type;
+	}
+
+	if (state->dest_decl) {
+		new_id = NULL;
+		if ((new_type = calloc(1, sizeof(*new_type))) == NULL) {
+			goto cleanup;
+		}
+		new_type->primary = type->primary;
+		new_type->flavor = type->flavor;
+		new_type->flags = type->flags;
+		new_type->s.value = base_type->s.value;
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+		if (hashtab_insert
+		    (state->dest_decl->p_types.table, new_id, new_type)) {
+			goto cleanup;
+		}
+		state->dest_decl->p_types.nprim++;
+	}
+
+	state->cur->map[SYM_TYPES][type->s.value - 1] = base_type->s.value;
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	free(new_id);
+	free(new_type);
+	return -1;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id = key, *new_id = NULL;
+	user_datum_t *user, *base_user, *new_user = NULL;
+	link_state_t *state = (link_state_t *) data;
+
+	user = (user_datum_t *) datum;
+
+	base_user = hashtab_search(state->base->p_users.table, id);
+	if (base_user == NULL) {
+		if (state->verbose)
+			INFO(state->handle, "copying user %s", id);
+
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+
+		if ((new_user =
+		     (user_datum_t *) malloc(sizeof(*new_user))) == NULL) {
+			goto cleanup;
+		}
+		user_datum_init(new_user);
+		/* new_users's roles and MLS fields will be copied during
+		   user_fix_callback(). */
+
+		new_user->s.value = state->base->p_users.nprim + 1;
+
+		ret = hashtab_insert(state->base->p_users.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_user);
+		if (ret) {
+			goto cleanup;
+		}
+		state->base->p_users.nprim++;
+		base_user = new_user;
+	}
+
+	if (state->dest_decl) {
+		new_id = NULL;
+		if ((new_user = malloc(sizeof(*new_user))) == NULL) {
+			goto cleanup;
+		}
+		user_datum_init(new_user);
+		new_user->s.value = base_user->s.value;
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+		if (hashtab_insert
+		    (state->dest_decl->p_users.table, new_id, new_user)) {
+			goto cleanup;
+		}
+		state->dest_decl->p_users.nprim++;
+	}
+
+	state->cur->map[SYM_USERS][user->s.value - 1] = base_user->s.value;
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	user_datum_destroy(new_user);
+	free(new_id);
+	free(new_user);
+	return -1;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	int ret;
+	char *id = key, *new_id = NULL;
+	cond_bool_datum_t *booldatum, *base_bool, *new_bool = NULL;
+	link_state_t *state = (link_state_t *) data;
+	scope_datum_t *scope;
+
+	booldatum = (cond_bool_datum_t *) datum;
+
+	base_bool = hashtab_search(state->base->p_bools.table, id);
+	if (base_bool == NULL) {
+		if (state->verbose)
+			INFO(state->handle, "copying boolean %s", id);
+
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+
+		if ((new_bool =
+		     (cond_bool_datum_t *) malloc(sizeof(*new_bool))) == NULL) {
+			goto cleanup;
+		}
+		new_bool->s.value = state->base->p_bools.nprim + 1;
+
+		ret = hashtab_insert(state->base->p_bools.table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_bool);
+		if (ret) {
+			goto cleanup;
+		}
+		state->base->p_bools.nprim++;
+		base_bool = new_bool;
+		base_bool->flags = booldatum->flags;
+		base_bool->state = booldatum->state;
+	} else if ((booldatum->flags & COND_BOOL_FLAGS_TUNABLE) !=
+		   (base_bool->flags & COND_BOOL_FLAGS_TUNABLE)) {
+			/* A mismatch between boolean/tunable declaration
+			 * and usage(for example a boolean used in the
+			 * tunable_policy() or vice versa).
+			 *
+			 * This is not allowed and bail out with errors */
+			ERR(state->handle,
+			    "%s: Mismatch between boolean/tunable definition "
+			    "and usage for %s", state->cur_mod_name, id);
+			return -1;
+	}
+
+	/* Get the scope info for this boolean to see if this is the declaration, 
+ 	 * if so set the state */
+	scope = hashtab_search(state->cur->policy->p_bools_scope.table, id);
+	if (!scope)
+		return SEPOL_ERR;
+	if (scope->scope == SCOPE_DECL) {
+		base_bool->state = booldatum->state;
+		/* Only the declaration rather than requirement
+		 * decides if it is a boolean or tunable. */
+		base_bool->flags = booldatum->flags;
+	}
+	state->cur->map[SYM_BOOLS][booldatum->s.value - 1] = base_bool->s.value;
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	cond_destroy_bool(new_id, new_bool, NULL);
+	return -1;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			      void *data)
+{
+	char *id = key;
+	level_datum_t *level, *base_level;
+	link_state_t *state = (link_state_t *) data;
+	scope_datum_t *scope;
+
+	level = (level_datum_t *) datum;
+
+	base_level = hashtab_search(state->base->p_levels.table, id);
+	if (!base_level) {
+		scope =
+		    hashtab_search(state->cur->policy->p_sens_scope.table, id);
+		if (!scope)
+			return SEPOL_ERR;
+		if (scope->scope == SCOPE_DECL) {
+			/* disallow declarations in modules */
+			ERR(state->handle,
+			    "%s: Modules may not declare new sensitivities.",
+			    state->cur_mod_name);
+			return SEPOL_ENOTSUP;
+		} else if (scope->scope == SCOPE_REQ) {
+			/* unmet requirement */
+			ERR(state->handle,
+			    "%s: Sensitivity %s not declared by base.",
+			    state->cur_mod_name, id);
+			return SEPOL_ENOTSUP;
+		} else {
+			ERR(state->handle,
+			    "%s: has an unknown scope: %d\n",
+			    state->cur_mod_name, scope->scope);
+			return SEPOL_ENOTSUP;
+		}
+	}
+
+	state->cur->map[SYM_LEVELS][level->level->sens - 1] =
+	    base_level->level->sens;
+
+	return 0;
+}
+
+static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	char *id = key;
+	cat_datum_t *cat, *base_cat;
+	link_state_t *state = (link_state_t *) data;
+	scope_datum_t *scope;
+
+	cat = (cat_datum_t *) datum;
+
+	base_cat = hashtab_search(state->base->p_cats.table, id);
+	if (!base_cat) {
+		scope = hashtab_search(state->cur->policy->p_cat_scope.table, id);
+		if (!scope)
+			return SEPOL_ERR;
+		if (scope->scope == SCOPE_DECL) {
+			/* disallow declarations in modules */
+			ERR(state->handle,
+			    "%s: Modules may not declare new categories.",
+			    state->cur_mod_name);
+			return SEPOL_ENOTSUP;
+		} else if (scope->scope == SCOPE_REQ) {
+			/* unmet requirement */
+			ERR(state->handle,
+			    "%s: Category %s not declared by base.",
+			    state->cur_mod_name, id);
+			return SEPOL_ENOTSUP;
+		} else {
+			/* unknown scope?  malformed policy? */
+			ERR(state->handle,
+			    "%s: has an unknown scope: %d\n",
+			    state->cur_mod_name, scope->scope);
+			return SEPOL_ENOTSUP;
+		}
+	}
+
+	state->cur->map[SYM_CATS][cat->s.value - 1] = base_cat->s.value;
+
+	return 0;
+}
+
+static int (*copy_callback_f[SYM_NUM]) (hashtab_key_t key,
+					hashtab_datum_t datum, void *datap) = {
+NULL, class_copy_callback, role_copy_callback, type_copy_callback,
+	    user_copy_callback, bool_copy_callback, sens_copy_callback,
+	    cat_copy_callback};
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!type->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_TYPES][type->bounds - 1];
+
+	dest = hashtab_search(state->base->p_types.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	role_datum_t *role = (role_datum_t *) datum;
+	role_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!role->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_ROLES][role->bounds - 1];
+
+	dest = hashtab_search(state->base->p_roles.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "Role lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	user_datum_t *user = (user_datum_t *) datum;
+	user_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!user->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_USERS][user->bounds - 1];
+
+	dest = hashtab_search(state->base->p_users.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "User lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be
+ * certain that the base symbol table will have the type that the
+ * alias refers. Otherwise, we won't be able to find the type value
+ * for the alias. We can't depend on the declaration ordering because
+ * of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			       void *data)
+{
+	char *id = key, *new_id = NULL, *target_id;
+	type_datum_t *type, *base_type, *new_type = NULL, *target_type;
+	link_state_t *state = (link_state_t *) data;
+	policy_module_t *mod = state->cur;
+	int primval;
+
+	type = (type_datum_t *) datum;
+	/* there are 2 kinds of aliases. Ones with their own value (TYPE_ALIAS)
+	 * and ones with the value of their primary (TYPE_TYPE && type->primary = 0)
+	 */
+	if (!
+	    (type->flavor == TYPE_ALIAS
+	     || (type->flavor == TYPE_TYPE && !type->primary))) {
+		/* ignore types and attributes -- they were handled in
+		 * type_copy_callback() */
+		return 0;
+	}
+
+	if (type->flavor == TYPE_ALIAS)
+		primval = type->primary;
+	else
+		primval = type->s.value;
+
+	target_id = mod->policy->p_type_val_to_name[primval - 1];
+	target_type = hashtab_search(state->base->p_types.table, target_id);
+	if (target_type == NULL) {
+		ERR(state->handle, "%s: Could not find type %s for alias %s.",
+		    state->cur_mod_name, target_id, id);
+		return -1;
+	}
+
+	if (!strcmp(id, target_id)) {
+		ERR(state->handle, "%s: Self aliasing of %s.",
+		    state->cur_mod_name, id);
+		return -1;
+	}
+
+	target_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+
+	base_type = hashtab_search(state->base->p_types.table, id);
+	if (base_type == NULL) {
+		if (state->verbose)
+			INFO(state->handle, "copying alias %s", id);
+
+		if ((new_type =
+		     (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+			goto cleanup;
+		}
+		/* the linked copy always has TYPE_ALIAS style aliases */
+		new_type->primary = target_type->s.value;
+		new_type->flags = target_type->flags;
+		new_type->flavor = TYPE_ALIAS;
+		new_type->s.value = state->base->p_types.nprim + 1;
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+		if (hashtab_insert
+		    (state->base->p_types.table, new_id, new_type)) {
+			goto cleanup;
+		}
+		state->base->p_types.nprim++;
+		base_type = new_type;
+	} else {
+
+		/* if this already exists and isn't an alias it was required by another module (or base)
+		 * and inserted into the hashtable as a type, fix it up now */
+
+		if (base_type->flavor == TYPE_ALIAS) {
+			/* error checking */
+			assert(base_type->primary == target_type->s.value);
+			assert(base_type->primary ==
+			       mod->map[SYM_TYPES][primval - 1]);
+			assert(mod->map[SYM_TYPES][type->s.value - 1] ==
+			       base_type->primary);
+			return 0;
+		}
+
+		if (base_type->flavor == TYPE_ATTRIB) {
+			ERR(state->handle,
+			    "%s is an alias of an attribute, not allowed", id);
+			return -1;
+		}
+
+		base_type->flavor = TYPE_ALIAS;
+		base_type->primary = target_type->s.value;
+		base_type->flags |= (target_type->flags & TYPE_FLAGS_PERMISSIVE);
+
+	}
+	/* the aliases map points from its value to its primary so when this module 
+	 * references this type the value it gets back from the map is the primary */
+	mod->map[SYM_TYPES][type->s.value - 1] = base_type->primary;
+
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	free(new_id);
+	free(new_type);
+	return -1;
+}
+
+/*********** callbacks that fix bitmaps ***********/
+
+static int type_set_convert(type_set_t * types, type_set_t * dst,
+			    policy_module_t * mod, link_state_t * state
+			    __attribute__ ((unused)))
+{
+	unsigned int i;
+	ebitmap_node_t *tnode;
+	ebitmap_for_each_bit(&types->types, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			assert(mod->map[SYM_TYPES][i]);
+			if (ebitmap_set_bit
+			    (&dst->types, mod->map[SYM_TYPES][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	ebitmap_for_each_bit(&types->negset, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			assert(mod->map[SYM_TYPES][i]);
+			if (ebitmap_set_bit
+			    (&dst->negset, mod->map[SYM_TYPES][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	dst->flags = types->flags;
+	return 0;
+
+      cleanup:
+	return -1;
+}
+
+/* OR 2 typemaps together and at the same time map the src types to
+ * the correct values in the dst typeset.
+ */
+static int type_set_or_convert(type_set_t * types, type_set_t * dst,
+			       policy_module_t * mod, link_state_t * state)
+{
+	type_set_t ts_tmp;
+
+	type_set_init(&ts_tmp);
+	if (type_set_convert(types, &ts_tmp, mod, state) == -1) {
+		goto cleanup;
+	}
+	if (type_set_or_eq(dst, &ts_tmp)) {
+		goto cleanup;
+	}
+	type_set_destroy(&ts_tmp);
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	type_set_destroy(&ts_tmp);
+	return -1;
+}
+
+static int role_set_or_convert(role_set_t * roles, role_set_t * dst,
+			       policy_module_t * mod, link_state_t * state)
+{
+	unsigned int i;
+	ebitmap_t tmp;
+	ebitmap_node_t *rnode;
+
+	ebitmap_init(&tmp);
+	ebitmap_for_each_bit(&roles->roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			assert(mod->map[SYM_ROLES][i]);
+			if (ebitmap_set_bit
+			    (&tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	if (ebitmap_union(&dst->roles, &tmp)) {
+		goto cleanup;
+	}
+	dst->flags |= roles->flags;
+	ebitmap_destroy(&tmp);
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	ebitmap_destroy(&tmp);
+	return -1;
+}
+
+static int mls_level_convert(mls_semantic_level_t * src, mls_semantic_level_t * dst,
+			     policy_module_t * mod, link_state_t * state)
+{
+	mls_semantic_cat_t *src_cat, *new_cat;
+
+	if (!mod->policy->mls)
+		return 0;
+
+	/* Required not declared. */
+	if (!src->sens)
+		return 0;
+
+	assert(mod->map[SYM_LEVELS][src->sens - 1]);
+	dst->sens = mod->map[SYM_LEVELS][src->sens - 1];
+
+	for (src_cat = src->cat; src_cat; src_cat = src_cat->next) {
+		new_cat =
+		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+		if (!new_cat) {
+			ERR(state->handle, "Out of memory");
+			return -1;
+		}
+		mls_semantic_cat_init(new_cat);
+
+		new_cat->next = dst->cat;
+		dst->cat = new_cat;
+
+		assert(mod->map[SYM_CATS][src_cat->low - 1]);
+		dst->cat->low = mod->map[SYM_CATS][src_cat->low - 1];
+		assert(mod->map[SYM_CATS][src_cat->high - 1]);
+		dst->cat->high = mod->map[SYM_CATS][src_cat->high - 1];
+	}
+
+	return 0;
+}
+
+static int mls_range_convert(mls_semantic_range_t * src, mls_semantic_range_t * dst,
+			     policy_module_t * mod, link_state_t * state)
+{
+	int ret;
+	ret = mls_level_convert(&src->level[0], &dst->level[0], mod, state);
+	if (ret)
+		return ret;
+	ret = mls_level_convert(&src->level[1], &dst->level[1], mod, state);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	unsigned int i;
+	char *id = key;
+	role_datum_t *role, *dest_role = NULL;
+	link_state_t *state = (link_state_t *) data;
+	ebitmap_t e_tmp;
+	policy_module_t *mod = state->cur;
+	ebitmap_node_t *rnode;
+	hashtab_t role_tab;
+
+	role = (role_datum_t *) datum;
+	if (state->dest_decl == NULL)
+		role_tab = state->base->p_roles.table;
+	else
+		role_tab = state->dest_decl->p_roles.table;
+
+	dest_role = hashtab_search(role_tab, id);
+	assert(dest_role != NULL);
+
+	if (state->verbose) {
+		INFO(state->handle, "fixing role %s", id);
+	}
+
+	ebitmap_init(&e_tmp);
+	ebitmap_for_each_bit(&role->dominates, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			assert(mod->map[SYM_ROLES][i]);
+			if (ebitmap_set_bit
+			    (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	if (ebitmap_union(&dest_role->dominates, &e_tmp)) {
+		goto cleanup;
+	}
+	if (type_set_or_convert(&role->types, &dest_role->types, mod, state)) {
+		goto cleanup;
+	}
+	ebitmap_destroy(&e_tmp);
+	
+	if (role->flavor == ROLE_ATTRIB) {
+		ebitmap_init(&e_tmp);
+		ebitmap_for_each_bit(&role->roles, rnode, i) {
+			if (ebitmap_node_get_bit(rnode, i)) {
+				assert(mod->map[SYM_ROLES][i]);
+				if (ebitmap_set_bit
+				    (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+					goto cleanup;
+				}
+			}
+		}
+		if (ebitmap_union(&dest_role->roles, &e_tmp)) {
+			goto cleanup;
+		}
+		ebitmap_destroy(&e_tmp);
+	}
+
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	ebitmap_destroy(&e_tmp);
+	return -1;
+}
+
+static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	unsigned int i;
+	char *id = key;
+	type_datum_t *type, *new_type = NULL;
+	link_state_t *state = (link_state_t *) data;
+	ebitmap_t e_tmp;
+	policy_module_t *mod = state->cur;
+	ebitmap_node_t *tnode;
+	symtab_t *typetab;
+
+	type = (type_datum_t *) datum;
+
+	if (state->dest_decl == NULL)
+		typetab = &state->base->p_types;
+	else
+		typetab = &state->dest_decl->p_types;
+
+	/* only fix attributes */
+	if (type->flavor != TYPE_ATTRIB) {
+		return 0;
+	}
+
+	new_type = hashtab_search(typetab->table, id);
+	assert(new_type != NULL && new_type->flavor == TYPE_ATTRIB);
+
+	if (state->verbose) {
+		INFO(state->handle, "fixing attribute %s", id);
+	}
+
+	ebitmap_init(&e_tmp);
+	ebitmap_for_each_bit(&type->types, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			assert(mod->map[SYM_TYPES][i]);
+			if (ebitmap_set_bit
+			    (&e_tmp, mod->map[SYM_TYPES][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	if (ebitmap_union(&new_type->types, &e_tmp)) {
+		goto cleanup;
+	}
+	ebitmap_destroy(&e_tmp);
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	ebitmap_destroy(&e_tmp);
+	return -1;
+}
+
+static int user_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+			     void *data)
+{
+	char *id = key;
+	user_datum_t *user, *new_user = NULL;
+	link_state_t *state = (link_state_t *) data;
+	policy_module_t *mod = state->cur;
+	symtab_t *usertab;
+
+	user = (user_datum_t *) datum;
+
+	if (state->dest_decl == NULL)
+		usertab = &state->base->p_users;
+	else
+		usertab = &state->dest_decl->p_users;
+
+	new_user = hashtab_search(usertab->table, id);
+	assert(new_user != NULL);
+
+	if (state->verbose) {
+		INFO(state->handle, "fixing user %s", id);
+	}
+
+	if (role_set_or_convert(&user->roles, &new_user->roles, mod, state)) {
+		goto cleanup;
+	}
+
+	if (mls_range_convert(&user->range, &new_user->range, mod, state))
+		goto cleanup;
+
+	if (mls_level_convert(&user->dfltlevel, &new_user->dfltlevel, mod, state))
+		goto cleanup;
+
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	return -1;
+}
+
+static int (*fix_callback_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+				       void *datap) = {
+NULL, NULL, role_fix_callback, type_fix_callback, user_fix_callback,
+	    NULL, NULL, NULL};
+
+/*********** functions that copy AV rules ***********/
+
+static int copy_avrule_list(avrule_t * list, avrule_t ** dst,
+			    policy_module_t * module, link_state_t * state)
+{
+	unsigned int i;
+	avrule_t *cur, *new_rule = NULL, *tail;
+	class_perm_node_t *cur_perm, *new_perm, *tail_perm = NULL;
+
+	tail = *dst;
+	while (tail && tail->next) {
+		tail = tail->next;
+	}
+
+	cur = list;
+	while (cur) {
+		if ((new_rule = (avrule_t *) malloc(sizeof(avrule_t))) == NULL) {
+			goto cleanup;
+		}
+		avrule_init(new_rule);
+
+		new_rule->specified = cur->specified;
+		new_rule->flags = cur->flags;
+		if (type_set_convert
+		    (&cur->stypes, &new_rule->stypes, module, state) == -1
+		    || type_set_convert(&cur->ttypes, &new_rule->ttypes, module,
+					state) == -1) {
+			goto cleanup;
+		}
+
+		cur_perm = cur->perms;
+		tail_perm = NULL;
+		while (cur_perm) {
+			if ((new_perm = (class_perm_node_t *)
+			     malloc(sizeof(class_perm_node_t))) == NULL) {
+				goto cleanup;
+			}
+			class_perm_node_init(new_perm);
+
+			new_perm->tclass =
+			    module->map[SYM_CLASSES][cur_perm->tclass - 1];
+			assert(new_perm->tclass);
+
+			if (new_rule->specified & AVRULE_AV) {
+				for (i = 0;
+				     i <
+				     module->perm_map_len[cur_perm->tclass - 1];
+				     i++) {
+					if (!(cur_perm->data & (1U << i)))
+						continue;
+					new_perm->data |=
+					    (1U <<
+					     (module->
+					      perm_map[cur_perm->tclass - 1][i] -
+					      1));
+				}
+			} else {
+				new_perm->data =
+				    module->map[SYM_TYPES][cur_perm->data - 1];
+			}
+
+			if (new_rule->perms == NULL) {
+				new_rule->perms = new_perm;
+			} else {
+				assert(tail_perm);
+				tail_perm->next = new_perm;
+			}
+			tail_perm = new_perm;
+			cur_perm = cur_perm->next;
+		}
+		new_rule->line = cur->line;
+		new_rule->source_line = cur->source_line;
+		if (cur->source_filename) {
+			new_rule->source_filename = strdup(cur->source_filename);
+			if (!new_rule->source_filename)
+				goto cleanup;
+		}
+
+		cur = cur->next;
+
+		if (*dst == NULL) {
+			*dst = new_rule;
+		} else {
+			tail->next = new_rule;
+		}
+		tail = new_rule;
+	}
+
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	avrule_destroy(new_rule);
+	free(new_rule);
+	return -1;
+}
+
+static int copy_role_trans_list(role_trans_rule_t * list,
+				role_trans_rule_t ** dst,
+				policy_module_t * module, link_state_t * state)
+{
+	role_trans_rule_t *cur, *new_rule = NULL, *tail;
+	unsigned int i;
+	ebitmap_node_t *cnode;
+
+	cur = list;
+	tail = *dst;
+	while (tail && tail->next) {
+		tail = tail->next;
+	}
+	while (cur) {
+		if ((new_rule =
+		     (role_trans_rule_t *) malloc(sizeof(role_trans_rule_t))) ==
+		    NULL) {
+			goto cleanup;
+		}
+		role_trans_rule_init(new_rule);
+
+		if (role_set_or_convert
+		    (&cur->roles, &new_rule->roles, module, state)
+		    || type_set_or_convert(&cur->types, &new_rule->types,
+					   module, state)) {
+			goto cleanup;
+		}
+
+		ebitmap_for_each_bit(&cur->classes, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				assert(module->map[SYM_CLASSES][i]);
+				if (ebitmap_set_bit(&new_rule->classes,
+						    module->
+						    map[SYM_CLASSES][i] - 1,
+						    1)) {
+					goto cleanup;
+				}
+			}
+		}
+
+		new_rule->new_role = module->map[SYM_ROLES][cur->new_role - 1];
+
+		if (*dst == NULL) {
+			*dst = new_rule;
+		} else {
+			tail->next = new_rule;
+		}
+		tail = new_rule;
+		cur = cur->next;
+	}
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	role_trans_rule_list_destroy(new_rule);
+	return -1;
+}
+
+static int copy_role_allow_list(role_allow_rule_t * list,
+				role_allow_rule_t ** dst,
+				policy_module_t * module, link_state_t * state)
+{
+	role_allow_rule_t *cur, *new_rule = NULL, *tail;
+
+	cur = list;
+	tail = *dst;
+	while (tail && tail->next) {
+		tail = tail->next;
+	}
+
+	while (cur) {
+		if ((new_rule =
+		     (role_allow_rule_t *) malloc(sizeof(role_allow_rule_t))) ==
+		    NULL) {
+			goto cleanup;
+		}
+		role_allow_rule_init(new_rule);
+
+		if (role_set_or_convert
+		    (&cur->roles, &new_rule->roles, module, state)
+		    || role_set_or_convert(&cur->new_roles,
+					   &new_rule->new_roles, module,
+					   state)) {
+			goto cleanup;
+		}
+		if (*dst == NULL) {
+			*dst = new_rule;
+		} else {
+			tail->next = new_rule;
+		}
+		tail = new_rule;
+		cur = cur->next;
+	}
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	role_allow_rule_list_destroy(new_rule);
+	return -1;
+}
+
+static int copy_filename_trans_list(filename_trans_rule_t * list,
+				    filename_trans_rule_t ** dst,
+				    policy_module_t * module,
+				    link_state_t * state)
+{
+	filename_trans_rule_t *cur, *new_rule, *tail;
+
+	cur = list;
+	tail = *dst;
+	while (tail && tail->next)
+		tail = tail->next;
+
+	while (cur) {
+		new_rule = malloc(sizeof(*new_rule));
+		if (!new_rule)
+			goto err;
+
+		filename_trans_rule_init(new_rule);
+
+		if (*dst == NULL)
+			*dst = new_rule;
+		else
+			tail->next = new_rule;
+		tail = new_rule;
+
+		new_rule->name = strdup(cur->name);
+		if (!new_rule->name)
+			goto err;
+
+		if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module, state) ||
+		    type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module, state))
+			goto err;
+
+		new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1];
+		new_rule->otype = module->map[SYM_TYPES][cur->otype - 1];
+
+		cur = cur->next;
+	}
+	return 0;
+err:
+	ERR(state->handle, "Out of memory!");
+	return -1;
+}
+
+static int copy_range_trans_list(range_trans_rule_t * rules,
+				 range_trans_rule_t ** dst,
+				 policy_module_t * mod, link_state_t * state)
+{
+	range_trans_rule_t *rule, *new_rule = NULL;
+	unsigned int i;
+	ebitmap_node_t *cnode;
+
+	for (rule = rules; rule; rule = rule->next) {
+		new_rule =
+		    (range_trans_rule_t *) malloc(sizeof(range_trans_rule_t));
+		if (!new_rule)
+			goto cleanup;
+
+		range_trans_rule_init(new_rule);
+
+		new_rule->next = *dst;
+		*dst = new_rule;
+
+		if (type_set_convert(&rule->stypes, &new_rule->stypes,
+				     mod, state))
+			goto cleanup;
+
+		if (type_set_convert(&rule->ttypes, &new_rule->ttypes,
+				     mod, state))
+			goto cleanup;
+
+		ebitmap_for_each_bit(&rule->tclasses, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				assert(mod->map[SYM_CLASSES][i]);
+				if (ebitmap_set_bit
+				    (&new_rule->tclasses,
+				     mod->map[SYM_CLASSES][i] - 1, 1)) {
+					goto cleanup;
+				}
+			}
+		}
+
+		if (mls_range_convert(&rule->trange, &new_rule->trange, mod, state))
+			goto cleanup;
+	}
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	range_trans_rule_list_destroy(new_rule);
+	return -1;
+}
+
+static int copy_cond_list(cond_node_t * list, cond_node_t ** dst,
+			  policy_module_t * module, link_state_t * state)
+{
+	unsigned i;
+	cond_node_t *cur, *new_node = NULL, *tail;
+	cond_expr_t *cur_expr;
+	tail = *dst;
+	while (tail && tail->next)
+		tail = tail->next;
+
+	cur = list;
+	while (cur) {
+		new_node = (cond_node_t *) malloc(sizeof(cond_node_t));
+		if (!new_node) {
+			goto cleanup;
+		}
+		memset(new_node, 0, sizeof(cond_node_t));
+
+		new_node->cur_state = cur->cur_state;
+		new_node->expr = cond_copy_expr(cur->expr);
+		if (!new_node->expr)
+			goto cleanup;
+		/* go back through and remap the expression */
+		for (cur_expr = new_node->expr; cur_expr != NULL;
+		     cur_expr = cur_expr->next) {
+			/* expression nodes don't have a bool value of 0 - don't map them */
+			if (cur_expr->expr_type != COND_BOOL)
+				continue;
+			assert(module->map[SYM_BOOLS][cur_expr->bool - 1] != 0);
+			cur_expr->bool =
+			    module->map[SYM_BOOLS][cur_expr->bool - 1];
+		}
+		new_node->nbools = cur->nbools;
+		/* FIXME should COND_MAX_BOOLS be used here? */
+		for (i = 0; i < min(cur->nbools, COND_MAX_BOOLS); i++) {
+			uint32_t remapped_id =
+			    module->map[SYM_BOOLS][cur->bool_ids[i] - 1];
+			assert(remapped_id != 0);
+			new_node->bool_ids[i] = remapped_id;
+		}
+		new_node->expr_pre_comp = cur->expr_pre_comp;
+
+		if (copy_avrule_list
+		    (cur->avtrue_list, &new_node->avtrue_list, module, state)
+		    || copy_avrule_list(cur->avfalse_list,
+					&new_node->avfalse_list, module,
+					state)) {
+			goto cleanup;
+		}
+
+		if (*dst == NULL) {
+			*dst = new_node;
+		} else {
+			tail->next = new_node;
+		}
+		tail = new_node;
+		cur = cur->next;
+	}
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	cond_node_destroy(new_node);
+	free(new_node);
+	return -1;
+
+}
+
+/*********** functions that copy avrule_decls from module to base ***********/
+
+static int copy_identifiers(link_state_t * state, symtab_t * src_symtab,
+			    avrule_decl_t * dest_decl)
+{
+	int i, ret;
+
+	state->dest_decl = dest_decl;
+	for (i = 0; i < SYM_NUM; i++) {
+		if (copy_callback_f[i] != NULL) {
+			ret =
+			    hashtab_map(src_symtab[i].table, copy_callback_f[i],
+					state);
+			if (ret) {
+				return ret;
+			}
+		}
+	}
+
+	if (hashtab_map(src_symtab[SYM_TYPES].table,
+			type_bounds_copy_callback, state))
+		return -1;
+
+	if (hashtab_map(src_symtab[SYM_TYPES].table,
+			alias_copy_callback, state))
+		return -1;
+
+	if (hashtab_map(src_symtab[SYM_ROLES].table,
+			role_bounds_copy_callback, state))
+		return -1;
+
+	if (hashtab_map(src_symtab[SYM_USERS].table,
+			user_bounds_copy_callback, state))
+		return -1;
+
+	/* then fix bitmaps associated with those newly copied identifiers */
+	for (i = 0; i < SYM_NUM; i++) {
+		if (fix_callback_f[i] != NULL &&
+		    hashtab_map(src_symtab[i].table, fix_callback_f[i],
+				state)) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int copy_scope_index(scope_index_t * src, scope_index_t * dest,
+			    policy_module_t * module, link_state_t * state)
+{
+	unsigned int i, j;
+	uint32_t largest_mapped_class_value = 0;
+	ebitmap_node_t *node;
+	/* copy the scoping information for this avrule decl block */
+	for (i = 0; i < SYM_NUM; i++) {
+		ebitmap_t *srcmap = src->scope + i;
+		ebitmap_t *destmap = dest->scope + i;
+		if (copy_callback_f[i] == NULL) {
+			continue;
+		}
+		ebitmap_for_each_bit(srcmap, node, j) {
+			if (ebitmap_node_get_bit(node, j)) {
+				assert(module->map[i][j] != 0);
+				if (ebitmap_set_bit
+				    (destmap, module->map[i][j] - 1, 1) != 0) {
+
+					goto cleanup;
+				}
+				if (i == SYM_CLASSES &&
+				    largest_mapped_class_value <
+				    module->map[SYM_CLASSES][j]) {
+					largest_mapped_class_value =
+					    module->map[SYM_CLASSES][j];
+				}
+			}
+		}
+	}
+
+	/* next copy the enabled permissions data  */
+	if ((dest->class_perms_map = malloc(largest_mapped_class_value *
+					    sizeof(*dest->class_perms_map))) ==
+	    NULL) {
+		goto cleanup;
+	}
+	for (i = 0; i < largest_mapped_class_value; i++) {
+		ebitmap_init(dest->class_perms_map + i);
+	}
+	dest->class_perms_len = largest_mapped_class_value;
+	for (i = 0; i < src->class_perms_len; i++) {
+		ebitmap_t *srcmap = src->class_perms_map + i;
+		ebitmap_t *destmap =
+		    dest->class_perms_map + module->map[SYM_CLASSES][i] - 1;
+		ebitmap_for_each_bit(srcmap, node, j) {
+			if (ebitmap_node_get_bit(node, j) &&
+			    ebitmap_set_bit(destmap, module->perm_map[i][j] - 1,
+					    1)) {
+				goto cleanup;
+			}
+		}
+	}
+
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	return -1;
+}
+
+static int copy_avrule_decl(link_state_t * state, policy_module_t * module,
+			    avrule_decl_t * src_decl, avrule_decl_t * dest_decl)
+{
+	int ret;
+
+	/* copy all of the RBAC and TE rules */
+	if (copy_avrule_list
+	    (src_decl->avrules, &dest_decl->avrules, module, state) == -1
+	    || copy_role_trans_list(src_decl->role_tr_rules,
+				    &dest_decl->role_tr_rules, module,
+				    state) == -1
+	    || copy_role_allow_list(src_decl->role_allow_rules,
+				    &dest_decl->role_allow_rules, module,
+				    state) == -1
+	    || copy_cond_list(src_decl->cond_list, &dest_decl->cond_list,
+			      module, state) == -1) {
+		return -1;
+	}
+
+	if (copy_filename_trans_list(src_decl->filename_trans_rules,
+				     &dest_decl->filename_trans_rules,
+				     module, state))
+		return -1;
+
+	if (copy_range_trans_list(src_decl->range_tr_rules,
+				  &dest_decl->range_tr_rules, module, state))
+		return -1;
+
+	/* finally copy any identifiers local to this declaration */
+	ret = copy_identifiers(state, src_decl->symtab, dest_decl);
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* then copy required and declared scope indices here */
+	if (copy_scope_index(&src_decl->required, &dest_decl->required,
+			     module, state) == -1 ||
+	    copy_scope_index(&src_decl->declared, &dest_decl->declared,
+			     module, state) == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int copy_avrule_block(link_state_t * state, policy_module_t * module,
+			     avrule_block_t * block)
+{
+	avrule_block_t *new_block = avrule_block_create();
+	avrule_decl_t *decl, *last_decl = NULL;
+	int ret;
+
+	if (new_block == NULL) {
+		ERR(state->handle, "Out of memory!");
+		ret = -1;
+		goto cleanup;
+	}
+
+	new_block->flags = block->flags;
+
+	for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+		avrule_decl_t *new_decl =
+		    avrule_decl_create(state->next_decl_id);
+		if (new_decl == NULL) {
+			ERR(state->handle, "Out of memory!");
+			ret = -1;
+			goto cleanup;
+		}
+
+		if (module->policy->name != NULL) {
+			new_decl->module_name = strdup(module->policy->name);
+			if (new_decl->module_name == NULL) {
+				ERR(state->handle, "Out of memory\n");
+				avrule_decl_destroy(new_decl);
+				ret = -1;
+				goto cleanup;
+			}
+		}
+
+		if (last_decl == NULL) {
+			new_block->branch_list = new_decl;
+		} else {
+			last_decl->next = new_decl;
+		}
+		last_decl = new_decl;
+		state->base->decl_val_to_struct[state->next_decl_id - 1] =
+		    new_decl;
+		state->decl_to_mod[state->next_decl_id] = module->policy;
+
+		module->avdecl_map[decl->decl_id] = new_decl->decl_id;
+
+		ret = copy_avrule_decl(state, module, decl, new_decl);
+		if (ret) {
+			avrule_decl_destroy(new_decl);
+			goto cleanup;
+		}
+
+		state->next_decl_id++;
+	}
+	state->last_avrule_block->next = new_block;
+	state->last_avrule_block = new_block;
+	return 0;
+
+      cleanup:
+	avrule_block_list_destroy(new_block);
+	return ret;
+}
+
+static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+			       void *data)
+{
+	unsigned int i;
+	int ret;
+	char *id = key, *new_id = NULL;
+	scope_datum_t *scope, *base_scope;
+	link_state_t *state = (link_state_t *) data;
+	uint32_t symbol_num = state->symbol_num;
+	uint32_t *avdecl_map = state->cur->avdecl_map;
+
+	scope = (scope_datum_t *) datum;
+
+	/* check if the base already has a scope entry */
+	base_scope = hashtab_search(state->base->scope[symbol_num].table, id);
+	if (base_scope == NULL) {
+		scope_datum_t *new_scope;
+		if ((new_id = strdup(id)) == NULL) {
+			goto cleanup;
+		}
+
+		if ((new_scope =
+		     (scope_datum_t *) calloc(1, sizeof(*new_scope))) == NULL) {
+			free(new_id);
+			goto cleanup;
+		}
+		ret = hashtab_insert(state->base->scope[symbol_num].table,
+				     (hashtab_key_t) new_id,
+				     (hashtab_datum_t) new_scope);
+		if (ret) {
+			free(new_id);
+			free(new_scope);
+			goto cleanup;
+		}
+		new_scope->scope = SCOPE_REQ;	/* this is reset further down */
+		base_scope = new_scope;
+	}
+	if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_DECL) {
+		/* this module declared symbol, so overwrite the old
+		 * list with the new decl ids */
+		base_scope->scope = SCOPE_DECL;
+		free(base_scope->decl_ids);
+		base_scope->decl_ids = NULL;
+		base_scope->decl_ids_len = 0;
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+				       &base_scope->decl_ids_len,
+				       &base_scope->decl_ids) == -1) {
+				goto cleanup;
+			}
+		}
+	} else if (base_scope->scope == SCOPE_DECL && scope->scope == SCOPE_REQ) {
+		/* this module depended on a symbol that now exists,
+		 * so don't do anything */
+	} else if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_REQ) {
+		/* symbol is still required, so add to the list */
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+				       &base_scope->decl_ids_len,
+				       &base_scope->decl_ids) == -1) {
+				goto cleanup;
+			}
+		}
+	} else {
+		/* this module declared a symbol, and it was already
+		 * declared.  only roles and users may be multiply
+		 * declared; for all others this is an error. */
+		if (symbol_num != SYM_ROLES && symbol_num != SYM_USERS) {
+			ERR(state->handle,
+			    "%s: Duplicate declaration in module: %s %s",
+			    state->cur_mod_name,
+			    symtab_names[state->symbol_num], id);
+			return -1;
+		}
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+				       &base_scope->decl_ids_len,
+				       &base_scope->decl_ids) == -1) {
+				goto cleanup;
+			}
+		}
+	}
+	return 0;
+
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	return -1;
+}
+
+/* Copy a module over to a base, remapping all values within.  After
+ * all identifiers and rules are done, copy the scoping information.
+ * This is when it checks for duplicate declarations. */
+static int copy_module(link_state_t * state, policy_module_t * module)
+{
+	int i, ret;
+	avrule_block_t *cur;
+	state->cur = module;
+	state->cur_mod_name = module->policy->name;
+
+	/* first copy all of the identifiers */
+	ret = copy_identifiers(state, module->policy->symtab, NULL);
+	if (ret) {
+		return ret;
+	}
+
+	/* next copy all of the avrule blocks */
+	for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+		ret = copy_avrule_block(state, module, cur);
+		if (ret) {
+			return ret;
+		}
+	}
+
+	/* then copy the scoping tables */
+	for (i = 0; i < SYM_NUM; i++) {
+		state->symbol_num = i;
+		if (hashtab_map
+		    (module->policy->scope[i].table, scope_copy_callback,
+		     state)) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/***** functions that check requirements and enable blocks in a module ******/
+
+/* borrowed from checkpolicy.c */
+
+struct find_perm_arg {
+	unsigned int valuep;
+	hashtab_key_t key;
+};
+
+static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *varg)
+{
+
+	struct find_perm_arg *arg = varg;
+
+	perm_datum_t *perdatum = (perm_datum_t *) datum;
+	if (arg->valuep == perdatum->s.value) {
+		arg->key = key;
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Check if the requirements are met for a single declaration.  If all
+ * are met return 1.  For the first requirement found to be missing,
+ * if 'missing_sym_num' and 'missing_value' are both not NULL then
+ * write to them the symbol number and value for the missing
+ * declaration.  Then return 0 to indicate a missing declaration.
+ * Note that if a declaration had no requirement at all (e.g., an ELSE
+ * block) this returns 1. */
+static int is_decl_requires_met(link_state_t * state,
+				avrule_decl_t * decl,
+				struct missing_requirement *req)
+{
+	/* (This algorithm is very unoptimized.  It performs many
+	 * redundant checks.  A very obvious improvement is to cache
+	 * which symbols have been verified, so that they do not need
+	 * to be re-checked.) */
+	unsigned int i, j;
+	ebitmap_t *bitmap;
+	char *id, *perm_id;
+	policydb_t *pol = state->base;
+	ebitmap_node_t *node;
+
+	/* check that all symbols have been satisfied */
+	for (i = 0; i < SYM_NUM; i++) {
+		if (i == SYM_CLASSES) {
+			/* classes will be checked during permissions
+			 * checking phase below */
+			continue;
+		}
+		bitmap = &decl->required.scope[i];
+		ebitmap_for_each_bit(bitmap, node, j) {
+			if (!ebitmap_node_get_bit(node, j)) {
+				continue;
+			}
+
+			/* check base's scope table */
+			id = pol->sym_val_to_name[i][j];
+			if (!is_id_enabled(id, state->base, i)) {
+				/* this symbol was not found */
+				if (req != NULL) {
+					req->symbol_type = i;
+					req->symbol_value = j + 1;
+				}
+				return 0;
+			}
+		}
+	}
+	/* check that all classes and permissions have been satisfied */
+	for (i = 0; i < decl->required.class_perms_len; i++) {
+
+		bitmap = decl->required.class_perms_map + i;
+		ebitmap_for_each_bit(bitmap, node, j) {
+			struct find_perm_arg fparg;
+			class_datum_t *cladatum;
+			uint32_t perm_value = j + 1;
+			int rc;
+			scope_datum_t *scope;
+
+			if (!ebitmap_node_get_bit(node, j)) {
+				continue;
+			}
+			id = pol->p_class_val_to_name[i];
+			cladatum = pol->class_val_to_struct[i];
+
+			scope =
+			    hashtab_search(state->base->p_classes_scope.table,
+					   id);
+			if (scope == NULL) {
+				ERR(state->handle,
+				    "Could not find scope information for class %s",
+				    id);
+				return -1;
+			}
+
+			fparg.valuep = perm_value;
+			fparg.key = NULL;
+
+			(void)hashtab_map(cladatum->permissions.table, find_perm,
+				    &fparg);
+			if (fparg.key == NULL && cladatum->comdatum != NULL) {
+				rc = hashtab_map(cladatum->comdatum->permissions.table,
+						 find_perm, &fparg);
+				assert(rc == 1);
+			}
+			perm_id = fparg.key;
+
+			assert(perm_id != NULL);
+			if (!is_perm_enabled(id, perm_id, state->base)) {
+				if (req != NULL) {
+					req->symbol_type = SYM_CLASSES;
+					req->symbol_value = i + 1;
+					req->perm_value = perm_value;
+				}
+				return 0;
+			}
+		}
+	}
+
+	/* all requirements have been met */
+	return 1;
+}
+
+static int debug_requirements(link_state_t * state, policydb_t * p)
+{
+	int ret;
+	avrule_block_t *cur;
+	missing_requirement_t req;
+	memset(&req, 0, sizeof(req));
+
+	for (cur = p->global; cur != NULL; cur = cur->next) {
+		if (cur->enabled != NULL)
+			continue;
+
+		ret = is_decl_requires_met(state, cur->branch_list, &req);
+		if (ret < 0) {
+			return ret;
+		} else if (ret == 0) {
+			const char *mod_name = cur->branch_list->module_name ?
+			    cur->branch_list->module_name : "BASE";
+			if (req.symbol_type == SYM_CLASSES) {
+				struct find_perm_arg fparg;
+
+				class_datum_t *cladatum;
+				cladatum = p->class_val_to_struct[req.symbol_value - 1];
+
+				fparg.valuep = req.perm_value;
+				fparg.key = NULL;
+				(void)hashtab_map(cladatum->permissions.table,
+						  find_perm, &fparg);
+
+				if (cur->flags & AVRULE_OPTIONAL) {
+					ERR(state->handle,
+					    "%s[%d]'s optional requirements were not met: class %s, permission %s",
+					    mod_name, cur->branch_list->decl_id,
+					    p->p_class_val_to_name[req.symbol_value - 1],
+					    fparg.key);
+				} else {
+					ERR(state->handle,
+					    "%s[%d]'s global requirements were not met: class %s, permission %s",
+					    mod_name, cur->branch_list->decl_id,
+					    p->p_class_val_to_name[req.symbol_value - 1],
+					    fparg.key);
+				}
+			} else {
+				if (cur->flags & AVRULE_OPTIONAL) {
+					ERR(state->handle,
+					    "%s[%d]'s optional requirements were not met: %s %s",
+					    mod_name, cur->branch_list->decl_id,
+					    symtab_names[req.symbol_type],
+					    p->sym_val_to_name[req.
+							       symbol_type][req.
+									    symbol_value
+									    -
+									    1]);
+				} else {
+					ERR(state->handle,
+					    "%s[%d]'s global requirements were not met: %s %s",
+					    mod_name, cur->branch_list->decl_id,
+					    symtab_names[req.symbol_type],
+					    p->sym_val_to_name[req.
+							       symbol_type][req.
+									    symbol_value
+									    -
+									    1]);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static void print_missing_requirements(link_state_t * state,
+				       avrule_block_t * cur,
+				       missing_requirement_t * req)
+{
+	policydb_t *p = state->base;
+	const char *mod_name = cur->branch_list->module_name ?
+	    cur->branch_list->module_name : "BASE";
+
+	if (req->symbol_type == SYM_CLASSES) {
+
+		struct find_perm_arg fparg;
+
+		class_datum_t *cladatum;
+		cladatum = p->class_val_to_struct[req->symbol_value - 1];
+
+		fparg.valuep = req->perm_value;
+		fparg.key = NULL;
+		(void)hashtab_map(cladatum->permissions.table, find_perm, &fparg);
+
+		ERR(state->handle,
+		    "%s's global requirements were not met: class %s, permission %s",
+		    mod_name,
+		    p->p_class_val_to_name[req->symbol_value - 1], fparg.key);
+	} else {
+		ERR(state->handle,
+		    "%s's global requirements were not met: %s %s",
+		    mod_name,
+		    symtab_names[req->symbol_type],
+		    p->sym_val_to_name[req->symbol_type][req->symbol_value - 1]);
+	}
+}
+
+/* Enable all of the avrule_decl blocks for the policy. This simple
+ * algorithm is the following:
+ *
+ * 1) Enable all of the non-else avrule_decls for all blocks.
+ * 2) Iterate through the non-else decls looking for decls whose requirements
+ *    are not met.
+ *    2a) If the decl is non-optional, return immediately with an error.
+ *    2b) If the decl is optional, disable the block and mark changed = 1
+ * 3) If changed == 1 goto 2.
+ * 4) Iterate through all blocks looking for those that have no enabled
+ *    decl. If the block has an else decl, enable.
+ *
+ * This will correctly handle all dependencies, including mutual and
+ * cicular. The only downside is that it is slow.
+ */
+static int enable_avrules(link_state_t * state, policydb_t * pol)
+{
+	int changed = 1;
+	avrule_block_t *block;
+	avrule_decl_t *decl;
+	missing_requirement_t req;
+	int ret = 0, rc;
+
+	if (state->verbose) {
+		INFO(state->handle, "Determining which avrules to enable.");
+	}
+
+	/* 1) enable all of the non-else blocks */
+	for (block = pol->global; block != NULL; block = block->next) {
+		block->enabled = block->branch_list;
+		block->enabled->enabled = 1;
+		for (decl = block->branch_list->next; decl != NULL;
+		     decl = decl->next)
+			decl->enabled = 0;
+	}
+
+	/* 2) Iterate */
+	while (changed) {
+		changed = 0;
+		for (block = pol->global; block != NULL; block = block->next) {
+			if (block->enabled == NULL) {
+				continue;
+			}
+			decl = block->branch_list;
+			if (state->verbose) {
+				const char *mod_name = decl->module_name ?
+				    decl->module_name : "BASE";
+				INFO(state->handle, "check module %s decl %d\n",
+				     mod_name, decl->decl_id);
+			}
+			rc = is_decl_requires_met(state, decl, &req);
+			if (rc < 0) {
+				ret = SEPOL_ERR;
+				goto out;
+			} else if (rc == 0) {
+				decl->enabled = 0;
+				block->enabled = NULL;
+				changed = 1;
+				if (!(block->flags & AVRULE_OPTIONAL)) {
+					print_missing_requirements(state, block,
+								   &req);
+					ret = SEPOL_EREQ;
+					goto out;
+				}
+			}
+		}
+	}
+
+	/* 4) else handling
+	 *
+	 * Iterate through all of the blocks skipping the first (which is the
+	 * global block, is required to be present, and cannot have an else).
+	 * If the block is disabled and has an else decl, enable that.
+	 *
+	 * This code assumes that the second block in the branch list is the else
+	 * block. This is currently supported by the compiler.
+	 */
+	for (block = pol->global->next; block != NULL; block = block->next) {
+		if (block->enabled == NULL) {
+			if (block->branch_list->next != NULL) {
+				block->enabled = block->branch_list->next;
+				block->branch_list->next->enabled = 1;
+			}
+		}
+	}
+
+      out:
+	if (state->verbose)
+		debug_requirements(state, pol);
+
+	return ret;
+}
+
+/*********** the main linking functions ***********/
+
+/* Given a module's policy, normalize all conditional expressions
+ * within.  Return 0 on success, -1 on error. */
+static int cond_normalize(policydb_t * p)
+{
+	avrule_block_t *block;
+	for (block = p->global; block != NULL; block = block->next) {
+		avrule_decl_t *decl;
+		for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+			cond_list_t *cond = decl->cond_list;
+			while (cond) {
+				if (cond_normalize_expr(p, cond) < 0)
+					return -1;
+				cond = cond->next;
+			}
+		}
+	}
+	return 0;
+}
+
+/* Allocate space for the various remapping arrays. */
+static int prepare_module(link_state_t * state, policy_module_t * module)
+{
+	int i;
+	uint32_t items, num_decls = 0;
+	avrule_block_t *cur;
+
+	/* allocate the maps */
+	for (i = 0; i < SYM_NUM; i++) {
+		items = module->policy->symtab[i].nprim;
+		if ((module->map[i] =
+		     (uint32_t *) calloc(items,
+					 sizeof(*module->map[i]))) == NULL) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+	}
+
+	/* allocate the permissions remap here */
+	items = module->policy->p_classes.nprim;
+	if ((module->perm_map_len =
+	     calloc(items, sizeof(*module->perm_map_len))) == NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	if ((module->perm_map =
+	     calloc(items, sizeof(*module->perm_map))) == NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	/* allocate a map for avrule_decls */
+	for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+		avrule_decl_t *decl;
+		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+			if (decl->decl_id > num_decls) {
+				num_decls = decl->decl_id;
+			}
+		}
+	}
+	num_decls++;
+	if ((module->avdecl_map = calloc(num_decls, sizeof(uint32_t))) == NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	module->num_decls = num_decls;
+
+	/* normalize conditionals within */
+	if (cond_normalize(module->policy) < 0) {
+		ERR(state->handle,
+		    "Error while normalizing conditionals within the module %s.",
+		    module->policy->name);
+		return -1;
+	}
+	return 0;
+}
+
+static int prepare_base(link_state_t * state, uint32_t num_mod_decls)
+{
+	avrule_block_t *cur = state->base->global;
+	assert(cur != NULL);
+	state->next_decl_id = 0;
+
+	/* iterate through all of the declarations in the base, to
+	   determine what the next decl_id should be */
+	while (cur != NULL) {
+		avrule_decl_t *decl;
+		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+			if (decl->decl_id > state->next_decl_id) {
+				state->next_decl_id = decl->decl_id;
+			}
+		}
+		state->last_avrule_block = cur;
+		cur = cur->next;
+	}
+	state->last_base_avrule_block = state->last_avrule_block;
+	state->next_decl_id++;
+
+	/* allocate the table mapping from base's decl_id to its
+	 * avrule_decls and set the initial mappings */
+	free(state->base->decl_val_to_struct);
+	if ((state->base->decl_val_to_struct =
+	     calloc(state->next_decl_id + num_mod_decls,
+		    sizeof(*(state->base->decl_val_to_struct)))) == NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	/* This allocates the decl block to module mapping used for error reporting */
+	if ((state->decl_to_mod = calloc(state->next_decl_id + num_mod_decls,
+					 sizeof(*(state->decl_to_mod)))) ==
+	    NULL) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+	cur = state->base->global;
+	while (cur != NULL) {
+		avrule_decl_t *decl = cur->branch_list;
+		while (decl != NULL) {
+			state->base->decl_val_to_struct[decl->decl_id - 1] =
+			    decl;
+			state->decl_to_mod[decl->decl_id] = state->base;
+			decl = decl->next;
+		}
+		cur = cur->next;
+	}
+
+	/* normalize conditionals within */
+	if (cond_normalize(state->base) < 0) {
+		ERR(state->handle,
+		    "Error while normalizing conditionals within the base module.");
+		return -1;
+	}
+	return 0;
+}
+
+static int expand_role_attributes(hashtab_key_t key, hashtab_datum_t datum,
+				  void * data)
+{
+	char *id;
+	role_datum_t *role, *sub_attr;
+	link_state_t *state;
+	unsigned int i;
+	ebitmap_node_t *rnode;
+
+	id = key;
+	role = (role_datum_t *)datum;
+	state = (link_state_t *)data;
+
+	if (strcmp(id, OBJECT_R) == 0){
+		/* object_r is never a role attribute by far */
+		return 0;
+	}
+
+	if (role->flavor != ROLE_ATTRIB)
+		return 0;
+
+	if (state->verbose)
+		INFO(state->handle, "expanding role attribute %s", id);
+
+restart:
+	ebitmap_for_each_bit(&role->roles, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			sub_attr = state->base->role_val_to_struct[i];
+			if (sub_attr->flavor != ROLE_ATTRIB)
+				continue;
+			
+			/* remove the sub role attribute from the parent
+			 * role attribute's roles ebitmap */
+			if (ebitmap_set_bit(&role->roles, i, 0))
+				return -1;
+
+			/* loop dependency of role attributes */
+			if (sub_attr->s.value == role->s.value)
+				continue;
+
+			/* now go on to expand a sub role attribute
+			 * by escalating its roles ebitmap */
+			if (ebitmap_union(&role->roles, &sub_attr->roles)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			
+			/* sub_attr->roles may contain other role attributes,
+			 * re-scan the parent role attribute's roles ebitmap */
+			goto restart;
+		}
+	}
+
+	return 0;
+}
+
+/* For any role attribute in a declaration's local symtab[SYM_ROLES] table,
+ * copy its roles ebitmap into its duplicate's in the base->p_roles.table.
+ */
+static int populate_decl_roleattributes(hashtab_key_t key, 
+					hashtab_datum_t datum,
+					void *data)
+{
+	char *id = key;
+	role_datum_t *decl_role, *base_role;
+	link_state_t *state = (link_state_t *)data;
+
+	decl_role = (role_datum_t *)datum;
+
+	if (strcmp(id, OBJECT_R) == 0) {
+		/* object_r is never a role attribute by far */
+		return 0;
+	}
+
+	if (decl_role->flavor != ROLE_ATTRIB)
+		return 0;
+
+	base_role = (role_datum_t *)hashtab_search(state->base->p_roles.table,
+						   id);
+	assert(base_role != NULL && base_role->flavor == ROLE_ATTRIB);
+
+	if (ebitmap_union(&base_role->roles, &decl_role->roles)) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int populate_roleattributes(link_state_t *state, policydb_t *pol)
+{
+	avrule_block_t *block;
+	avrule_decl_t *decl;
+
+	if (state->verbose)
+		INFO(state->handle, "Populating role-attribute relationship "
+			    "from enabled declarations' local symtab.");
+
+	/* Iterate through all of the blocks skipping the first(which is the
+	 * global block, is required to be present and can't have an else).
+	 * If the block is disabled or not having an enabled decl, skip it.
+	 */
+	for (block = pol->global->next; block != NULL; block = block->next)
+	{
+		decl = block->enabled;
+		if (decl == NULL || decl->enabled == 0)
+			continue;
+
+		if (hashtab_map(decl->symtab[SYM_ROLES].table, 
+				populate_decl_roleattributes, state))
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Link a set of modules into a base module. This process is somewhat
+ * similar to an actual compiler: it requires a set of order dependent
+ * steps.  The base and every module must have been indexed prior to
+ * calling this function.
+ */
+int link_modules(sepol_handle_t * handle,
+		 policydb_t * b, policydb_t ** mods, int len, int verbose)
+{
+	int i, ret, retval = -1;
+	policy_module_t **modules = NULL;
+	link_state_t state;
+	uint32_t num_mod_decls = 0;
+
+	memset(&state, 0, sizeof(state));
+	state.base = b;
+	state.verbose = verbose;
+	state.handle = handle;
+
+	if (b->policy_type != POLICY_BASE) {
+		ERR(state.handle, "Target of link was not a base policy.");
+		return -1;
+	}
+
+	/* first allocate some space to hold the maps from module
+	 * symbol's value to the destination symbol value; then do
+	 * other preparation work */
+	if ((modules =
+	     (policy_module_t **) calloc(len, sizeof(*modules))) == NULL) {
+		ERR(state.handle, "Out of memory!");
+		return -1;
+	}
+	for (i = 0; i < len; i++) {
+		if (mods[i]->policy_type != POLICY_MOD) {
+			ERR(state.handle,
+			    "Tried to link in a policy that was not a module.");
+			goto cleanup;
+		}
+
+		if (mods[i]->mls != b->mls) {
+			if (b->mls)
+				ERR(state.handle,
+				    "Tried to link in a non-MLS module with an MLS base.");
+			else
+				ERR(state.handle,
+				    "Tried to link in an MLS module with a non-MLS base.");
+			goto cleanup;
+		}
+
+		if ((modules[i] =
+		     (policy_module_t *) calloc(1,
+						sizeof(policy_module_t))) ==
+		    NULL) {
+			ERR(state.handle, "Out of memory!");
+			goto cleanup;
+		}
+		modules[i]->policy = mods[i];
+		if (prepare_module(&state, modules[i]) == -1) {
+			goto cleanup;
+		}
+		num_mod_decls += modules[i]->num_decls;
+	}
+	if (prepare_base(&state, num_mod_decls) == -1) {
+		goto cleanup;
+	}
+
+	/* copy all types, declared and required */
+	for (i = 0; i < len; i++) {
+		state.cur = modules[i];
+		state.cur_mod_name = modules[i]->policy->name;
+		ret =
+		    hashtab_map(modules[i]->policy->p_types.table,
+				type_copy_callback, &state);
+		if (ret) {
+			retval = ret;
+			goto cleanup;
+		}
+	}
+
+	/* then copy everything else, including aliases, and fixup attributes */
+	for (i = 0; i < len; i++) {
+		state.cur = modules[i];
+		state.cur_mod_name = modules[i]->policy->name;
+		ret =
+		    copy_identifiers(&state, modules[i]->policy->symtab, NULL);
+		if (ret) {
+			retval = ret;
+			goto cleanup;
+		}
+	}
+
+	if (policydb_index_others(state.handle, state.base, 0)) {
+		ERR(state.handle, "Error while indexing others");
+		goto cleanup;
+	}
+
+	/* copy and remap the module's data over to base */
+	for (i = 0; i < len; i++) {
+		state.cur = modules[i];
+		ret = copy_module(&state, modules[i]);
+		if (ret) {
+			retval = ret;
+			goto cleanup;
+		}
+	}
+
+	/* re-index base, for symbols were added to symbol tables  */
+	if (policydb_index_classes(state.base)) {
+		ERR(state.handle, "Error while indexing classes");
+		goto cleanup;
+	}
+	if (policydb_index_others(state.handle, state.base, 0)) {
+		ERR(state.handle, "Error while indexing others");
+		goto cleanup;
+	}
+
+	if (enable_avrules(&state, state.base)) {
+		retval = SEPOL_EREQ;
+		goto cleanup;
+	}
+
+	/* Now that all role attribute's roles ebitmap have been settled,
+	 * escalate sub role attribute's roles ebitmap into that of parent.
+	 *
+	 * First, since some role-attribute relationships could be recorded
+	 * in some decl's local symtab(see get_local_role()), we need to
+	 * populate them up to the base.p_roles table. */
+	if (populate_roleattributes(&state, state.base)) {
+		retval = SEPOL_EREQ;
+		goto cleanup;
+	}
+	
+	/* Now do the escalation. */
+	if (hashtab_map(state.base->p_roles.table, expand_role_attributes,
+			&state))
+		goto cleanup;
+
+	retval = 0;
+      cleanup:
+	for (i = 0; modules != NULL && i < len; i++) {
+		policy_module_destroy(modules[i]);
+	}
+	free(modules);
+	free(state.decl_to_mod);
+	return retval;
+}
diff --git a/libsepol/src/mls.c b/libsepol/src/mls.c
new file mode 100644
index 0000000..1e84bb7
--- /dev/null
+++ b/libsepol/src/mls.c
@@ -0,0 +1,798 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/* 
+ * Implementation of the multi-level security (MLS) policy.
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/context.h>
+
+#include <stdlib.h>
+
+#include "handle.h"
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+int mls_to_string(sepol_handle_t * handle,
+		  const policydb_t * policydb,
+		  const context_struct_t * mls, char **str)
+{
+
+	char *ptr = NULL, *ptr2 = NULL;
+
+	/* Temporary buffer - length + NULL terminator */
+	int len = mls_compute_context_len(policydb, mls) + 1;
+
+	ptr = (char *)malloc(len);
+	if (ptr == NULL)
+		goto omem;
+
+	/* Final string w/ ':' cut off */
+	ptr2 = (char *)malloc(len - 1);
+	if (ptr2 == NULL)
+		goto omem;
+
+	mls_sid_to_context(policydb, mls, &ptr);
+	ptr -= len - 1;
+	strcpy(ptr2, ptr + 1);
+
+	free(ptr);
+	*str = ptr2;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not convert mls context to string");
+
+	free(ptr);
+	free(ptr2);
+	return STATUS_ERR;
+
+}
+
+int mls_from_string(sepol_handle_t * handle,
+		    const policydb_t * policydb,
+		    const char *str, context_struct_t * mls)
+{
+
+	char *tmp = strdup(str);
+	char *tmp_cp = tmp;
+	if (!tmp)
+		goto omem;
+
+	if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
+		ERR(handle, "invalid MLS context %s", str);
+		free(tmp);
+		goto err;
+	}
+
+	free(tmp);
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not construct mls context structure");
+	return STATUS_ERR;
+}
+
+/*
+ * Return the length in bytes for the MLS fields of the
+ * security context string representation of `context'.
+ */
+int mls_compute_context_len(const policydb_t * policydb,
+			    const context_struct_t * context)
+{
+
+	unsigned int i, l, len, range;
+	ebitmap_node_t *cnode;
+
+	if (!policydb->mls)
+		return 0;
+
+	len = 1;		/* for the beginning ":" */
+	for (l = 0; l < 2; l++) {
+		range = 0;
+		len +=
+		    strlen(policydb->
+			   p_sens_val_to_name[context->range.level[l].sens -
+					      1]);
+
+		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				if (range) {
+					range++;
+					continue;
+				}
+
+				len +=
+				    strlen(policydb->p_cat_val_to_name[i]) + 1;
+				range++;
+			} else {
+				if (range > 1)
+					len +=
+					    strlen(policydb->
+						   p_cat_val_to_name[i - 1]) +
+					    1;
+				range = 0;
+			}
+		}
+		/* Handle case where last category is the end of range */
+		if (range > 1)
+			len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
+
+		if (l == 0) {
+			if (mls_level_eq(&context->range.level[0],
+					 &context->range.level[1]))
+				break;
+			else
+				len++;
+		}
+	}
+
+	return len;
+}
+
+/*
+ * Write the security context string representation of
+ * the MLS fields of `context' into the string `*scontext'.
+ * Update `*scontext' to point to the end of the MLS fields.
+ */
+void mls_sid_to_context(const policydb_t * policydb,
+			const context_struct_t * context, char **scontext)
+{
+
+	char *scontextp;
+	unsigned int i, l, range, wrote_sep;
+	ebitmap_node_t *cnode;
+
+	if (!policydb->mls)
+		return;
+
+	scontextp = *scontext;
+
+	*scontextp = ':';
+	scontextp++;
+
+	for (l = 0; l < 2; l++) {
+		range = 0;
+		wrote_sep = 0;
+		strcpy(scontextp,
+		       policydb->p_sens_val_to_name[context->range.level[l].
+						    sens - 1]);
+		scontextp +=
+		    strlen(policydb->
+			   p_sens_val_to_name[context->range.level[l].sens -
+					      1]);
+		/* categories */
+		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				if (range) {
+					range++;
+					continue;
+				}
+
+				if (!wrote_sep) {
+					*scontextp++ = ':';
+					wrote_sep = 1;
+				} else
+					*scontextp++ = ',';
+				strcpy(scontextp,
+				       policydb->p_cat_val_to_name[i]);
+				scontextp +=
+				    strlen(policydb->p_cat_val_to_name[i]);
+				range++;
+			} else {
+				if (range > 1) {
+					if (range > 2)
+						*scontextp++ = '.';
+					else
+						*scontextp++ = ',';
+
+					strcpy(scontextp,
+					       policydb->p_cat_val_to_name[i -
+									   1]);
+					scontextp +=
+					    strlen(policydb->
+						   p_cat_val_to_name[i - 1]);
+				}
+				range = 0;
+			}
+		}
+		/* Handle case where last category is the end of range */
+		if (range > 1) {
+			if (range > 2)
+				*scontextp++ = '.';
+			else
+				*scontextp++ = ',';
+
+			strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
+			scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
+		}
+
+		if (l == 0) {
+			if (mls_level_eq(&context->range.level[0],
+					 &context->range.level[1]))
+				break;
+			else {
+				*scontextp = '-';
+				scontextp++;
+			}
+		}
+	}
+
+	*scontext = scontextp;
+	return;
+}
+
+/*
+ * Return 1 if the MLS fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+	level_datum_t *levdatum;
+	user_datum_t *usrdatum;
+	unsigned int i, l;
+	ebitmap_node_t *cnode;
+
+	if (!p->mls)
+		return 1;
+
+	/*
+	 * MLS range validity checks: high must dominate low, low level must
+	 * be valid (category set <-> sensitivity check), and high level must
+	 * be valid (category set <-> sensitivity check)
+	 */
+	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
+		/* High does not dominate low. */
+		return 0;
+
+	for (l = 0; l < 2; l++) {
+		if (!c->range.level[l].sens
+		    || c->range.level[l].sens > p->p_levels.nprim)
+			return 0;
+		levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+							    p->
+							    p_sens_val_to_name
+							    [c->range.level[l].
+							     sens - 1]);
+		if (!levdatum)
+			return 0;
+
+		ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				if (i > p->p_cats.nprim)
+					return 0;
+				if (!ebitmap_get_bit(&levdatum->level->cat, i))
+					/*
+					 * Category may not be associated with
+					 * sensitivity in low level.
+					 */
+					return 0;
+			}
+		}
+	}
+
+	if (c->role == OBJECT_R_VAL)
+		return 1;
+
+	/*
+	 * User must be authorized for the MLS range.
+	 */
+	if (!c->user || c->user > p->p_users.nprim)
+		return 0;
+	usrdatum = p->user_val_to_struct[c->user - 1];
+	if (!mls_range_contains(usrdatum->exp_range, c->range))
+		return 0;	/* user may not be associated with range */
+
+	return 1;
+}
+
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'.  Update `*scontext' to
+ * point to the end of the string representation of
+ * the MLS fields.
+ *
+ * This function modifies the string in place, inserting
+ * NULL characters to terminate the MLS fields.
+ */
+int mls_context_to_sid(const policydb_t * policydb,
+		       char oldc, char **scontext, context_struct_t * context)
+{
+
+	char delim;
+	char *scontextp, *p, *rngptr;
+	level_datum_t *levdatum;
+	cat_datum_t *catdatum, *rngdatum;
+	unsigned int l;
+
+	if (!policydb->mls)
+		return 0;
+
+	/* No MLS component to the security context */
+	if (!oldc)
+		goto err;
+
+	/* Extract low sensitivity. */
+	scontextp = p = *scontext;
+	while (*p && *p != ':' && *p != '-')
+		p++;
+
+	delim = *p;
+	if (delim != 0)
+		*p++ = 0;
+
+	for (l = 0; l < 2; l++) {
+		levdatum =
+		    (level_datum_t *) hashtab_search(policydb->p_levels.table,
+						     (hashtab_key_t) scontextp);
+
+		if (!levdatum)
+			goto err;
+
+		context->range.level[l].sens = levdatum->level->sens;
+
+		if (delim == ':') {
+			/* Extract category set. */
+			while (1) {
+				scontextp = p;
+				while (*p && *p != ',' && *p != '-')
+					p++;
+				delim = *p;
+				if (delim != 0)
+					*p++ = 0;
+
+				/* Separate into range if exists */
+				if ((rngptr = strchr(scontextp, '.')) != NULL) {
+					/* Remove '.' */
+					*rngptr++ = 0;
+				}
+
+				catdatum =
+				    (cat_datum_t *) hashtab_search(policydb->
+								   p_cats.table,
+								   (hashtab_key_t)
+								   scontextp);
+				if (!catdatum)
+					goto err;
+
+				if (ebitmap_set_bit
+				    (&context->range.level[l].cat,
+				     catdatum->s.value - 1, 1))
+					goto err;
+
+				/* If range, set all categories in range */
+				if (rngptr) {
+					unsigned int i;
+
+					rngdatum = (cat_datum_t *)
+					    hashtab_search(policydb->p_cats.
+							   table,
+							   (hashtab_key_t)
+							   rngptr);
+					if (!rngdatum)
+						goto err;
+
+					if (catdatum->s.value >=
+					    rngdatum->s.value)
+						goto err;
+
+					for (i = catdatum->s.value;
+					     i < rngdatum->s.value; i++) {
+						if (ebitmap_set_bit
+						    (&context->range.level[l].
+						     cat, i, 1))
+							goto err;
+					}
+				}
+
+				if (delim != ',')
+					break;
+			}
+		}
+		if (delim == '-') {
+			/* Extract high sensitivity. */
+			scontextp = p;
+			while (*p && *p != ':')
+				p++;
+
+			delim = *p;
+			if (delim != 0)
+				*p++ = 0;
+		} else
+			break;
+	}
+
+	/* High level is missing, copy low level */
+	if (l == 0) {
+		if (mls_level_cpy(&context->range.level[1],
+				  &context->range.level[0]) < 0)
+			goto err;
+	}
+	*scontext = ++p;
+
+	return STATUS_SUCCESS;
+
+      err:
+	return STATUS_ERR;
+}
+
+/*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(context_struct_t * dst,
+				   context_struct_t * src)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range from the source context */
+	for (l = 0; l < 2; l++) {
+		dst->range.level[l].sens = src->range.level[l].sens;
+		rc = ebitmap_cpy(&dst->range.level[l].cat,
+				 &src->range.level[l].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(context_struct_t * dst,
+				    context_struct_t * src)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range from the source context */
+	for (l = 0; l < 2; l++) {
+		dst->range.level[l].sens = src->range.level[0].sens;
+		rc = ebitmap_cpy(&dst->range.level[l].cat,
+				 &src->range.level[0].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(context_struct_t * context, mls_range_t * range)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range into the  context */
+	for (l = 0; l < 2; l++) {
+		context->range.level[l].sens = range->level[l].sens;
+		rc = ebitmap_cpy(&context->range.level[l].cat,
+				 &range->level[l].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+			 context_struct_t * usercon, int mls)
+{
+	if (mls) {
+		mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
+		mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
+		mls_level_t *user_low = &(user->exp_range.level[0]);
+		mls_level_t *user_clr = &(user->exp_range.level[1]);
+		mls_level_t *user_def = &(user->exp_dfltlevel);
+		mls_level_t *usercon_sen = &(usercon->range.level[0]);
+		mls_level_t *usercon_clr = &(usercon->range.level[1]);
+
+		/* Honor the user's default level if we can */
+		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+			*usercon_sen = *user_def;
+		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+			*usercon_sen = *fromcon_sen;
+		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+			*usercon_sen = *user_low;
+		} else
+			return -EINVAL;
+
+		/* Lower the clearance of available contexts
+		   if the clearance of "fromcon" is lower than
+		   that of the user's default clearance (but
+		   only if the "fromcon" clearance dominates
+		   the user's computed sensitivity level) */
+		if (mls_level_dom(user_clr, fromcon_clr)) {
+			*usercon_clr = *fromcon_clr;
+		} else if (mls_level_dom(fromcon_clr, user_clr)) {
+			*usercon_clr = *user_clr;
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Convert the MLS fields in the security context
+ * structure `c' from the values specified in the
+ * policy `oldp' to the values specified in the policy `newp'.
+ */
+int mls_convert_context(policydb_t * oldp,
+			policydb_t * newp, context_struct_t * c)
+{
+	level_datum_t *levdatum;
+	cat_datum_t *catdatum;
+	ebitmap_t bitmap;
+	unsigned int l, i;
+	ebitmap_node_t *cnode;
+
+	if (!oldp->mls)
+		return 0;
+
+	for (l = 0; l < 2; l++) {
+		levdatum =
+		    (level_datum_t *) hashtab_search(newp->p_levels.table,
+						     oldp->
+						     p_sens_val_to_name[c->
+									range.
+									level
+									[l].
+									sens -
+									1]);
+
+		if (!levdatum)
+			return -EINVAL;
+		c->range.level[l].sens = levdatum->level->sens;
+
+		ebitmap_init(&bitmap);
+		ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+			if (ebitmap_node_get_bit(cnode, i)) {
+				int rc;
+
+				catdatum =
+				    (cat_datum_t *) hashtab_search(newp->p_cats.
+								   table,
+								   oldp->
+								   p_cat_val_to_name
+								   [i]);
+				if (!catdatum)
+					return -EINVAL;
+				rc = ebitmap_set_bit(&bitmap,
+						     catdatum->s.value - 1, 1);
+				if (rc)
+					return rc;
+			}
+		}
+		ebitmap_destroy(&c->range.level[l].cat);
+		c->range.level[l].cat = bitmap;
+	}
+
+	return 0;
+}
+
+int mls_compute_sid(policydb_t * policydb,
+		    context_struct_t * scontext,
+		    context_struct_t * tcontext,
+		    sepol_security_class_t tclass,
+		    uint32_t specified, context_struct_t * newcontext)
+{
+	range_trans_t *rtr;
+	if (!policydb->mls)
+		return 0;
+
+	switch (specified) {
+	case AVTAB_TRANSITION:
+		/* Look for a range transition rule. */
+		for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
+			if (rtr->source_type == scontext->type &&
+			    rtr->target_type == tcontext->type &&
+			    rtr->target_class == tclass) {
+				/* Set the range from the rule */
+				return mls_range_set(newcontext,
+						     &rtr->target_range);
+			}
+		}
+		/* Fallthrough */
+	case AVTAB_CHANGE:
+		if (tclass == SECCLASS_PROCESS)
+			/* Use the process MLS attributes. */
+			return mls_copy_context(newcontext, scontext);
+		else
+			/* Use the process effective MLS attributes. */
+			return mls_scopy_context(newcontext, scontext);
+	case AVTAB_MEMBER:
+		/* Only polyinstantiate the MLS attributes if
+		   the type is being polyinstantiated */
+		if (newcontext->type != tcontext->type) {
+			/* Use the process effective MLS attributes. */
+			return mls_scopy_context(newcontext, scontext);
+		} else {
+			/* Use the related object MLS attributes. */
+			return mls_copy_context(newcontext, tcontext);
+		}
+	default:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+int sepol_mls_contains(sepol_handle_t * handle,
+		       sepol_policydb_t * policydb,
+		       const char *mls1, const char *mls2, int *response)
+{
+
+	context_struct_t *ctx1 = NULL, *ctx2 = NULL;
+	ctx1 = malloc(sizeof(context_struct_t));
+	ctx2 = malloc(sizeof(context_struct_t));
+	if (ctx1 == NULL || ctx2 == NULL)
+		goto omem;
+	context_init(ctx1);
+	context_init(ctx2);
+
+	if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
+		goto err;
+
+	if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
+		goto err;
+
+	*response = mls_range_contains(ctx1->range, ctx2->range);
+	context_destroy(ctx1);
+	context_destroy(ctx2);
+	free(ctx1);
+	free(ctx2);
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not check if mls context %s contains %s",
+	    mls1, mls2);
+	context_destroy(ctx1);
+	context_destroy(ctx2);
+	free(ctx1);
+	free(ctx2);
+	return STATUS_ERR;
+}
+
+int sepol_mls_check(sepol_handle_t * handle,
+		    sepol_policydb_t * policydb, const char *mls)
+{
+
+	int ret;
+	context_struct_t *con = malloc(sizeof(context_struct_t));
+	if (!con) {
+		ERR(handle, "out of memory, could not check if "
+		    "mls context %s is valid", mls);
+		return STATUS_ERR;
+	}
+	context_init(con);
+
+	ret = mls_from_string(handle, &policydb->p, mls, con);
+	context_destroy(con);
+	free(con);
+	return ret;
+}
+
+void mls_semantic_cat_init(mls_semantic_cat_t * c)
+{
+	memset(c, 0, sizeof(mls_semantic_cat_t));
+}
+
+void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
+{
+	/* it's currently a simple struct - really nothing to destroy */
+	return;
+}
+
+void mls_semantic_level_init(mls_semantic_level_t * l)
+{
+	memset(l, 0, sizeof(mls_semantic_level_t));
+}
+
+void mls_semantic_level_destroy(mls_semantic_level_t * l)
+{
+	mls_semantic_cat_t *cur, *next;
+
+	if (l == NULL)
+		return;
+
+	next = l->cat;
+	while (next) {
+		cur = next;
+		next = cur->next;
+		mls_semantic_cat_destroy(cur);
+		free(cur);
+	}
+}
+
+int mls_semantic_level_cpy(mls_semantic_level_t * dst,
+			   mls_semantic_level_t * src)
+{
+	mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL;
+
+	mls_semantic_level_init(dst);
+	dst->sens = src->sens;
+	cat = src->cat;
+	while (cat) {
+		newcat =
+		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+		if (!newcat)
+			goto err;
+
+		mls_semantic_cat_init(newcat);
+		if (lnewcat)
+			lnewcat->next = newcat;
+		else
+			dst->cat = newcat;
+
+		newcat->low = cat->low;
+		newcat->high = cat->high;
+
+		lnewcat = newcat;
+		cat = cat->next;
+	}
+	return 0;
+
+      err:
+	mls_semantic_level_destroy(dst);
+	return -1;
+}
+
+void mls_semantic_range_init(mls_semantic_range_t * r)
+{
+	mls_semantic_level_init(&r->level[0]);
+	mls_semantic_level_init(&r->level[1]);
+}
+
+void mls_semantic_range_destroy(mls_semantic_range_t * r)
+{
+	mls_semantic_level_destroy(&r->level[0]);
+	mls_semantic_level_destroy(&r->level[1]);
+}
+
+int mls_semantic_range_cpy(mls_semantic_range_t * dst,
+			   mls_semantic_range_t * src)
+{
+	if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
+		return -1;
+
+	if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
+		mls_semantic_level_destroy(&dst->level[0]);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/libsepol/src/mls.h b/libsepol/src/mls.h
new file mode 100644
index 0000000..98da3d3
--- /dev/null
+++ b/libsepol/src/mls.h
@@ -0,0 +1,67 @@
+/* Author: Stephen Smalley, <sds@epoch.ncsc.mil> 
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * 
+ *      Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ *  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
+ */
+
+#ifndef _SEPOL_MLS_INTERNAL_H_
+#define _SEPOL_MLS_INTERNAL_H_
+
+#include "policydb_internal.h"
+#include <sepol/policydb/context.h>
+#include "handle.h"
+
+extern int mls_from_string(sepol_handle_t * handle,
+			   const policydb_t * policydb,
+			   const char *str, context_struct_t * mls);
+
+extern int mls_to_string(sepol_handle_t * handle,
+			 const policydb_t * policydb,
+			 const context_struct_t * mls, char **str);
+
+/* Deprecated */
+extern int mls_compute_context_len(const policydb_t * policydb,
+				   const context_struct_t * context);
+
+/* Deprecated */
+extern void mls_sid_to_context(const policydb_t * policydb,
+			       const context_struct_t * context,
+			       char **scontext);
+
+/* Deprecated */
+extern int mls_context_to_sid(const policydb_t * policydb,
+			      char oldc,
+			      char **scontext, context_struct_t * context);
+
+extern int mls_context_isvalid(const policydb_t * p,
+			       const context_struct_t * c);
+
+extern int mls_convert_context(policydb_t * oldp,
+			       policydb_t * newp, context_struct_t * context);
+
+extern int mls_compute_sid(policydb_t * policydb,
+			   context_struct_t * scontext,
+			   context_struct_t * tcontext,
+			   sepol_security_class_t tclass,
+			   uint32_t specified, context_struct_t * newcontext);
+
+extern int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+				context_struct_t * usercon, int mls);
+
+#endif
diff --git a/libsepol/src/module.c b/libsepol/src/module.c
new file mode 100644
index 0000000..1665ede
--- /dev/null
+++ b/libsepol/src/module.c
@@ -0,0 +1,1008 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ *         Jason Tang     <jtang@tresys.com>
+ *         Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2004-2005 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 "policydb_internal.h"
+#include "module_internal.h"
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/module.h>
+#include "debug.h"
+#include "private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
+#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
+#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
+#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
+
+static int policy_file_seek(struct policy_file *fp, size_t offset)
+{
+	switch (fp->type) {
+	case PF_USE_STDIO:
+		if (offset > LONG_MAX) {
+			errno = EFAULT;
+			return -1;
+		}
+		return fseek(fp->fp, (long)offset, SEEK_SET);
+	case PF_USE_MEMORY:
+		if (offset > fp->size) {
+			errno = EFAULT;
+			return -1;
+		}
+		fp->data -= fp->size - fp->len;
+		fp->data += offset;
+		fp->len = fp->size - offset;
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+static int policy_file_length(struct policy_file *fp, size_t *out)
+{
+	long prev_offset, end_offset;
+	int rc;
+	switch (fp->type) {
+	case PF_USE_STDIO:
+		prev_offset = ftell(fp->fp);
+		if (prev_offset < 0)
+			return prev_offset;
+		rc = fseek(fp->fp, 0L, SEEK_END);
+		if (rc < 0)
+			return rc;
+		end_offset = ftell(fp->fp);
+		if (end_offset < 0)
+			return end_offset;
+		rc = fseek(fp->fp, prev_offset, SEEK_SET);
+		if (rc < 0)
+			return rc;
+		*out = end_offset;
+		break;
+	case PF_USE_MEMORY:
+		*out = fp->size;
+		break;;
+	default:
+		*out = 0;
+		break;
+	}
+	return 0;
+}
+
+static int module_package_init(sepol_module_package_t * p)
+{
+	memset(p, 0, sizeof(sepol_module_package_t));
+	if (sepol_policydb_create(&p->policy))
+		return -1;
+
+	p->version = 1;
+	return 0;
+}
+
+static int set_char(char **field, char *data, size_t len)
+{
+	if (*field) {
+		free(*field);
+		*field = NULL;
+	}
+	if (len) {
+		*field = malloc(len);
+		if (!*field)
+			return -1;
+		memcpy(*field, data, len);
+	}
+	return 0;
+}
+
+int sepol_module_package_create(sepol_module_package_t ** p)
+{
+	int rc;
+
+	*p = calloc(1, sizeof(sepol_module_package_t));
+	if (!(*p))
+		return -1;
+
+	rc = module_package_init(*p);
+	if (rc < 0)
+		free(*p);
+
+	return rc;
+}
+
+hidden_def(sepol_module_package_create)
+
+/* Deallocates all memory associated with a module package, including
+ * the pointer itself.  Does nothing if p is NULL.
+ */
+void sepol_module_package_free(sepol_module_package_t * p)
+{
+	if (p == NULL)
+		return;
+
+	sepol_policydb_free(p->policy);
+	free(p->file_contexts);
+	free(p->seusers);
+	free(p->user_extra);
+	free(p->netfilter_contexts);
+	free(p);
+}
+
+hidden_def(sepol_module_package_free)
+
+char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
+{
+	return p->file_contexts;
+}
+
+size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
+{
+	return p->file_contexts_len;
+}
+
+char *sepol_module_package_get_seusers(sepol_module_package_t * p)
+{
+	return p->seusers;
+}
+
+size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
+{
+	return p->seusers_len;
+}
+
+char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
+{
+	return p->user_extra;
+}
+
+size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
+{
+	return p->user_extra_len;
+}
+
+char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
+{
+	return p->netfilter_contexts;
+}
+
+size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
+						       p)
+{
+	return p->netfilter_contexts_len;
+}
+
+int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+					   char *data, size_t len)
+{
+	if (set_char(&p->file_contexts, data, len))
+		return -1;
+
+	p->file_contexts_len = len;
+	return 0;
+}
+
+int sepol_module_package_set_seusers(sepol_module_package_t * p,
+				     char *data, size_t len)
+{
+	if (set_char(&p->seusers, data, len))
+		return -1;
+
+	p->seusers_len = len;
+	return 0;
+}
+
+int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+					char *data, size_t len)
+{
+	if (set_char(&p->user_extra, data, len))
+		return -1;
+
+	p->user_extra_len = len;
+	return 0;
+}
+
+int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
+						char *data, size_t len)
+{
+	if (set_char(&p->netfilter_contexts, data, len))
+		return -1;
+
+	p->netfilter_contexts_len = len;
+	return 0;
+}
+
+sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
+{
+	return p->policy;
+}
+
+/* Append each of the file contexts from each module to the base
+ * policy's file context.  'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_fc_len' is the length of base's file context; it
+ * too is a reference variable.  Return 0 on success, -1 if out of
+ * memory. */
+static int link_file_contexts(sepol_module_package_t * base,
+			      sepol_module_package_t ** modules,
+			      int num_modules)
+{
+	size_t fc_len;
+	int i;
+	char *s;
+
+	fc_len = base->file_contexts_len;
+	for (i = 0; i < num_modules; i++) {
+		fc_len += modules[i]->file_contexts_len;
+	}
+
+	if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
+		return -1;
+	}
+	base->file_contexts = s;
+	for (i = 0; i < num_modules; i++) {
+		memcpy(base->file_contexts + base->file_contexts_len,
+		       modules[i]->file_contexts,
+		       modules[i]->file_contexts_len);
+		base->file_contexts_len += modules[i]->file_contexts_len;
+	}
+	return 0;
+}
+
+/* Append each of the netfilter contexts from each module to the base
+ * policy's netfilter context.  'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_nc_len' is the length of base's netfilter contexts; it
+ * too is a reference variable.  Return 0 on success, -1 if out of
+ * memory. */
+static int link_netfilter_contexts(sepol_module_package_t * base,
+				   sepol_module_package_t ** modules,
+				   int num_modules)
+{
+	size_t base_nc_len;
+	int i;
+	char *base_context;
+
+	base_nc_len = base->netfilter_contexts_len;
+	for (i = 0; i < num_modules; i++) {
+		base_nc_len += modules[i]->netfilter_contexts_len;
+	}
+
+	if ((base_context =
+	     (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
+		return -1;
+	}
+	base->netfilter_contexts = base_context;
+	for (i = 0; i < num_modules; i++) {
+		memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
+		       modules[i]->netfilter_contexts,
+		       modules[i]->netfilter_contexts_len);
+		base->netfilter_contexts_len +=
+		    modules[i]->netfilter_contexts_len;
+	}
+	return 0;
+}
+
+/* Links the module packages into the base.  Returns 0 on success, -1
+ * if a requirement was not met, or -2 for all other errors. */
+int sepol_link_packages(sepol_handle_t * handle,
+			sepol_module_package_t * base,
+			sepol_module_package_t ** modules, int num_modules,
+			int verbose)
+{
+	policydb_t **mod_pols = NULL;
+	int i, retval;
+
+	if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
+		ERR(handle, "Out of memory!");
+		return -2;
+	}
+	for (i = 0; i < num_modules; i++) {
+		mod_pols[i] = &modules[i]->policy->p;
+	}
+
+	retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
+			      verbose);
+	free(mod_pols);
+	if (retval == -3) {
+		return -1;
+	} else if (retval < 0) {
+		return -2;
+	}
+
+	if (link_file_contexts(base, modules, num_modules) == -1) {
+		ERR(handle, "Out of memory!");
+		return -2;
+	}
+
+	if (link_netfilter_contexts(base, modules, num_modules) == -1) {
+		ERR(handle, "Out of memory!");
+		return -2;
+	}
+
+	return 0;
+}
+
+/* buf must be large enough - no checks are performed */
+#define _read_helper_bufsize BUFSIZ
+static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
+{
+	uint32_t offset, nel, read_len;
+	int rc;
+
+	offset = 0;
+	nel = bytes;
+
+	while (nel) {
+		if (nel < _read_helper_bufsize)
+			read_len = nel;
+		else
+			read_len = _read_helper_bufsize;
+		rc = next_entry(&buf[offset], file, read_len);
+		if (rc < 0)
+			return -1;
+		offset += read_len;
+		nel -= read_len;
+	}
+	return 0;
+}
+
+#define MAXSECTIONS 100
+
+/* Get the section offsets from a package file, offsets will be malloc'd to
+ * the appropriate size and the caller must free() them */
+static int module_package_read_offsets(sepol_module_package_t * mod,
+				       struct policy_file *file,
+				       size_t ** offsets, uint32_t * sections)
+{
+	uint32_t *buf = NULL, nsec;
+	unsigned i;
+	size_t *off = NULL;
+	int rc;
+
+	buf = malloc(sizeof(uint32_t)*3);
+	if (!buf) {
+		ERR(file->handle, "out of memory");
+		goto err;
+	}
+	  
+	rc = next_entry(buf, file, sizeof(uint32_t) * 3);
+	if (rc < 0) {
+		ERR(file->handle, "module package header truncated");
+		goto err;
+	}
+	if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
+		ERR(file->handle,
+		    "wrong magic number for module package:  expected %#08x, got %#08x",
+		    SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
+		goto err;
+	}
+
+	mod->version = le32_to_cpu(buf[1]);
+	nsec = *sections = le32_to_cpu(buf[2]);
+
+	if (nsec > MAXSECTIONS) {
+		ERR(file->handle, "too many sections (%u) in module package",
+		    nsec);
+		goto err;
+	}
+
+	off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
+	if (!off) {
+		ERR(file->handle, "out of memory");
+		goto err;
+	}
+
+	free(buf);
+	buf = malloc(sizeof(uint32_t) * nsec);
+	if (!buf) {
+		ERR(file->handle, "out of memory");
+		goto err;
+	}
+	rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
+	if (rc < 0) {
+		ERR(file->handle, "module package offset array truncated");
+		goto err;
+	}
+
+	for (i = 0; i < nsec; i++) {
+		off[i] = le32_to_cpu(buf[i]);
+		if (i && off[i] < off[i - 1]) {
+			ERR(file->handle, "offsets are not increasing (at %u, "
+			    "offset %zu -> %zu", i, off[i - 1],
+			    off[i]);
+			goto err;
+		}
+	}
+
+	rc = policy_file_length(file, &off[nsec]);
+	if (rc < 0)
+		goto err;
+
+	if (nsec && off[nsec] < off[nsec-1]) {
+		ERR(file->handle, "offset greater than file size (at %u, "
+		    "offset %zu -> %zu", nsec, off[nsec - 1],
+		    off[nsec]);
+		goto err;
+	}
+	*offsets = off;
+	free(buf);
+	return 0;
+
+err:
+	free(buf);
+	free(off);
+	return -1;
+}
+
+/* Flags for which sections have been seen during parsing of module package. */
+#define SEEN_MOD 1
+#define SEEN_FC  2
+#define SEEN_SEUSER 4
+#define SEEN_USER_EXTRA 8
+#define SEEN_NETFILTER 16
+
+int sepol_module_package_read(sepol_module_package_t * mod,
+			      struct sepol_policy_file *spf, int verbose)
+{
+	struct policy_file *file = &spf->pf;
+	uint32_t buf[1], nsec;
+	size_t *offsets, len;
+	int rc;
+	unsigned i, seen = 0;
+
+	if (module_package_read_offsets(mod, file, &offsets, &nsec))
+		return -1;
+
+	/* we know the section offsets, seek to them and read in the data */
+
+	for (i = 0; i < nsec; i++) {
+
+		if (policy_file_seek(file, offsets[i])) {
+			ERR(file->handle, "error seeking to offset %zu for "
+			    "module package section %u", offsets[i], i);
+			goto cleanup;
+		}
+
+		len = offsets[i + 1] - offsets[i];
+
+		if (len < sizeof(uint32_t)) {
+			ERR(file->handle, "module package section %u "
+			    "has too small length %zu", i, len);
+			goto cleanup;
+		}
+
+		/* read the magic number, so that we know which function to call */
+		rc = next_entry(buf, file, sizeof(uint32_t));
+		if (rc < 0) {
+			ERR(file->handle,
+			    "module package section %u truncated, lacks magic number",
+			    i);
+			goto cleanup;
+		}
+
+		switch (le32_to_cpu(buf[0])) {
+		case SEPOL_PACKAGE_SECTION_FC:
+			if (seen & SEEN_FC) {
+				ERR(file->handle,
+				    "found multiple file contexts sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			mod->file_contexts_len = len - sizeof(uint32_t);
+			mod->file_contexts =
+			    (char *)malloc(mod->file_contexts_len);
+			if (!mod->file_contexts) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			if (read_helper
+			    (mod->file_contexts, file,
+			     mod->file_contexts_len)) {
+				ERR(file->handle,
+				    "invalid file contexts section at section %u",
+				    i);
+				free(mod->file_contexts);
+				mod->file_contexts = NULL;
+				goto cleanup;
+			}
+			seen |= SEEN_FC;
+			break;
+		case SEPOL_PACKAGE_SECTION_SEUSER:
+			if (seen & SEEN_SEUSER) {
+				ERR(file->handle,
+				    "found multiple seuser sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			mod->seusers_len = len - sizeof(uint32_t);
+			mod->seusers = (char *)malloc(mod->seusers_len);
+			if (!mod->seusers) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			if (read_helper(mod->seusers, file, mod->seusers_len)) {
+				ERR(file->handle,
+				    "invalid seuser section at section %u", i);
+				free(mod->seusers);
+				mod->seusers = NULL;
+				goto cleanup;
+			}
+			seen |= SEEN_SEUSER;
+			break;
+		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+			if (seen & SEEN_USER_EXTRA) {
+				ERR(file->handle,
+				    "found multiple user_extra sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			mod->user_extra_len = len - sizeof(uint32_t);
+			mod->user_extra = (char *)malloc(mod->user_extra_len);
+			if (!mod->user_extra) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			if (read_helper
+			    (mod->user_extra, file, mod->user_extra_len)) {
+				ERR(file->handle,
+				    "invalid user_extra section at section %u",
+				    i);
+				free(mod->user_extra);
+				mod->user_extra = NULL;
+				goto cleanup;
+			}
+			seen |= SEEN_USER_EXTRA;
+			break;
+		case SEPOL_PACKAGE_SECTION_NETFILTER:
+			if (seen & SEEN_NETFILTER) {
+				ERR(file->handle,
+				    "found multiple netfilter contexts sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			mod->netfilter_contexts_len = len - sizeof(uint32_t);
+			mod->netfilter_contexts =
+			    (char *)malloc(mod->netfilter_contexts_len);
+			if (!mod->netfilter_contexts) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			if (read_helper
+			    (mod->netfilter_contexts, file,
+			     mod->netfilter_contexts_len)) {
+				ERR(file->handle,
+				    "invalid netfilter contexts section at section %u",
+				    i);
+				free(mod->netfilter_contexts);
+				mod->netfilter_contexts = NULL;
+				goto cleanup;
+			}
+			seen |= SEEN_NETFILTER;
+			break;
+		case POLICYDB_MOD_MAGIC:
+			if (seen & SEEN_MOD) {
+				ERR(file->handle,
+				    "found multiple module sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			/* seek back to where the magic number was */
+			if (policy_file_seek(file, offsets[i]))
+				goto cleanup;
+
+			rc = policydb_read(&mod->policy->p, file, verbose);
+			if (rc < 0) {
+				ERR(file->handle,
+				    "invalid module in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			seen |= SEEN_MOD;
+			break;
+		default:
+			/* unknown section, ignore */
+			ERR(file->handle,
+			    "unknown magic number at section %u, offset: %zx, number: %ux ",
+			    i, offsets[i], le32_to_cpu(buf[0]));
+			break;
+		}
+	}
+
+	if ((seen & SEEN_MOD) == 0) {
+		ERR(file->handle, "missing module in module package");
+		goto cleanup;
+	}
+
+	free(offsets);
+	return 0;
+
+      cleanup:
+	free(offsets);
+	return -1;
+}
+
+int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
+			      char **name, char **version)
+{
+	struct policy_file *file = &spf->pf;
+	sepol_module_package_t *mod = NULL;
+	uint32_t buf[5], len, nsec;
+	size_t *offsets = NULL;
+	unsigned i, seen = 0;
+	char *id;
+	int rc;
+
+	if (sepol_module_package_create(&mod))
+		return -1;
+
+	if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
+		goto cleanup;
+	}
+
+	for (i = 0; i < nsec; i++) {
+
+		if (policy_file_seek(file, offsets[i])) {
+			ERR(file->handle, "error seeking to offset "
+			    "%zu for module package section %u", offsets[i], i);
+			goto cleanup;
+		}
+
+		len = offsets[i + 1] - offsets[i];
+
+		if (len < sizeof(uint32_t)) {
+			ERR(file->handle,
+			    "module package section %u has too small length %u",
+			    i, len);
+			goto cleanup;
+		}
+
+		/* read the magic number, so that we know which function to call */
+		rc = next_entry(buf, file, sizeof(uint32_t) * 2);
+		if (rc < 0) {
+			ERR(file->handle,
+			    "module package section %u truncated, lacks magic number",
+			    i);
+			goto cleanup;
+		}
+
+		switch (le32_to_cpu(buf[0])) {
+		case SEPOL_PACKAGE_SECTION_FC:
+			/* skip file contexts */
+			if (seen & SEEN_FC) {
+				ERR(file->handle,
+				    "found multiple file contexts sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			seen |= SEEN_FC;
+			break;
+		case SEPOL_PACKAGE_SECTION_SEUSER:
+			/* skip seuser */
+			if (seen & SEEN_SEUSER) {
+				ERR(file->handle,
+				    "found seuser sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			seen |= SEEN_SEUSER;
+			break;
+		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+			/* skip user_extra */
+			if (seen & SEEN_USER_EXTRA) {
+				ERR(file->handle,
+				    "found user_extra sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			seen |= SEEN_USER_EXTRA;
+			break;
+		case SEPOL_PACKAGE_SECTION_NETFILTER:
+			/* skip netfilter contexts */
+			if (seen & SEEN_NETFILTER) {
+				ERR(file->handle,
+				    "found multiple netfilter contexts sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			seen |= SEEN_NETFILTER;
+			break;
+		case POLICYDB_MOD_MAGIC:
+			if (seen & SEEN_MOD) {
+				ERR(file->handle,
+				    "found multiple module sections in module package (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			len = le32_to_cpu(buf[1]);
+			if (len != strlen(POLICYDB_MOD_STRING)) {
+				ERR(file->handle,
+				    "module string length is wrong (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			/* skip id */
+			id = malloc(len + 1);
+			if (!id) {
+				ERR(file->handle,
+				    "out of memory (at section %u)",
+				    i);
+				goto cleanup;				
+			}
+			rc = next_entry(id, file, len);
+			free(id);
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module string (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			
+			rc = next_entry(buf, file, sizeof(uint32_t) * 5);
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module header (at section %u)",
+				    i);
+				goto cleanup;
+			}
+
+			*type = le32_to_cpu(buf[0]);
+			/* if base - we're done */
+			if (*type == POLICY_BASE) {
+				*name = NULL;
+				*version = NULL;
+				seen |= SEEN_MOD;
+				break;
+			} else if (*type != POLICY_MOD) {
+				ERR(file->handle,
+				    "module has invalid type %d (at section %u)",
+				    *type, i);
+				goto cleanup;
+			}
+
+			/* read the name and version */
+			rc = next_entry(buf, file, sizeof(uint32_t));
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module name len (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			len = le32_to_cpu(buf[0]);
+			*name = malloc(len + 1);
+			if (!*name) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			rc = next_entry(*name, file, len);
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module name string (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			(*name)[len] = '\0';
+			rc = next_entry(buf, file, sizeof(uint32_t));
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module version len (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			len = le32_to_cpu(buf[0]);
+			*version = malloc(len + 1);
+			if (!*version) {
+				ERR(file->handle, "out of memory");
+				goto cleanup;
+			}
+			rc = next_entry(*version, file, len);
+			if (rc < 0) {
+				ERR(file->handle,
+				    "cannot get module version string (at section %u)",
+				    i);
+				goto cleanup;
+			}
+			(*version)[len] = '\0';
+			seen |= SEEN_MOD;
+			break;
+		default:
+			break;
+		}
+
+	}
+
+	if ((seen & SEEN_MOD) == 0) {
+		ERR(file->handle, "missing module in module package");
+		goto cleanup;
+	}
+
+	sepol_module_package_free(mod);
+	free(offsets);
+	return 0;
+
+      cleanup:
+	sepol_module_package_free(mod);
+	free(offsets);
+	return -1;
+}
+
+static int write_helper(char *data, size_t len, struct policy_file *file)
+{
+	int idx = 0;
+	size_t len2;
+
+	while (len) {
+		if (len > BUFSIZ)
+			len2 = BUFSIZ;
+		else
+			len2 = len;
+
+		if (put_entry(&data[idx], 1, len2, file) != len2) {
+			return -1;
+		}
+		len -= len2;
+		idx += len2;
+	}
+	return 0;
+}
+
+int sepol_module_package_write(sepol_module_package_t * p,
+			       struct sepol_policy_file *spf)
+{
+	struct policy_file *file = &spf->pf;
+	policy_file_t polfile;
+	uint32_t buf[5], offsets[5], len, nsec = 0;
+	int i;
+
+	if (p->policy) {
+		/* compute policy length */
+		policy_file_init(&polfile);
+		polfile.type = PF_LEN;
+		polfile.handle = file->handle;
+		if (policydb_write(&p->policy->p, &polfile))
+			return -1;
+		len = polfile.len;
+		if (!polfile.len)
+			return -1;
+		nsec++;
+
+	} else {
+		/* We don't support writing a package without a module at this point */
+		return -1;
+	}
+
+	/* seusers and user_extra only supported in base at the moment */
+	if ((p->seusers || p->user_extra)
+	    && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
+		ERR(file->handle,
+		    "seuser and user_extra sections only supported in base");
+		return -1;
+	}
+
+	if (p->file_contexts)
+		nsec++;
+
+	if (p->seusers)
+		nsec++;
+
+	if (p->user_extra)
+		nsec++;
+
+	if (p->netfilter_contexts)
+		nsec++;
+
+	buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
+	buf[1] = cpu_to_le32(p->version);
+	buf[2] = cpu_to_le32(nsec);
+	if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
+		return -1;
+
+	/* calculate offsets */
+	offsets[0] = (nsec + 3) * sizeof(uint32_t);
+	buf[0] = cpu_to_le32(offsets[0]);
+
+	i = 1;
+	if (p->file_contexts) {
+		offsets[i] = offsets[i - 1] + len;
+		buf[i] = cpu_to_le32(offsets[i]);
+		/* add a uint32_t to compensate for the magic number */
+		len = p->file_contexts_len + sizeof(uint32_t);
+		i++;
+	}
+	if (p->seusers) {
+		offsets[i] = offsets[i - 1] + len;
+		buf[i] = cpu_to_le32(offsets[i]);
+		len = p->seusers_len + sizeof(uint32_t);
+		i++;
+	}
+	if (p->user_extra) {
+		offsets[i] = offsets[i - 1] + len;
+		buf[i] = cpu_to_le32(offsets[i]);
+		len = p->user_extra_len + sizeof(uint32_t);
+		i++;
+	}
+	if (p->netfilter_contexts) {
+		offsets[i] = offsets[i - 1] + len;
+		buf[i] = cpu_to_le32(offsets[i]);
+		len = p->netfilter_contexts_len + sizeof(uint32_t);
+		i++;
+	}
+	if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
+		return -1;
+
+	/* write sections */
+
+	if (policydb_write(&p->policy->p, file))
+		return -1;
+
+	if (p->file_contexts) {
+		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
+		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+			return -1;
+		if (write_helper(p->file_contexts, p->file_contexts_len, file))
+			return -1;
+	}
+	if (p->seusers) {
+		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
+		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+			return -1;
+		if (write_helper(p->seusers, p->seusers_len, file))
+			return -1;
+
+	}
+	if (p->user_extra) {
+		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
+		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+			return -1;
+		if (write_helper(p->user_extra, p->user_extra_len, file))
+			return -1;
+	}
+	if (p->netfilter_contexts) {
+		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
+		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+			return -1;
+		if (write_helper
+		    (p->netfilter_contexts, p->netfilter_contexts_len, file))
+			return -1;
+	}
+	return 0;
+}
+
+int sepol_link_modules(sepol_handle_t * handle,
+		       sepol_policydb_t * base,
+		       sepol_policydb_t ** modules, size_t len, int verbose)
+{
+	return link_modules(handle, &base->p, (policydb_t **) modules, len,
+			    verbose);
+}
+
+int sepol_expand_module(sepol_handle_t * handle,
+			sepol_policydb_t * base,
+			sepol_policydb_t * out, int verbose, int check)
+{
+	return expand_module(handle, &base->p, &out->p, verbose, check);
+}
diff --git a/libsepol/src/module_internal.h b/libsepol/src/module_internal.h
new file mode 100644
index 0000000..cdd5ec6
--- /dev/null
+++ b/libsepol/src/module_internal.h
@@ -0,0 +1,5 @@
+#include <sepol/module.h>
+#include "dso.h"
+
+hidden_proto(sepol_module_package_create)
+    hidden_proto(sepol_module_package_free)
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
new file mode 100644
index 0000000..b9a4af7
--- /dev/null
+++ b/libsepol/src/module_to_cil.c
@@ -0,0 +1,4097 @@
+/* Authors: Steve Lawrence <slawrence@tresys.com>
+ *
+ * Functions to convert policy module to CIL
+ *
+ * Copyright (C) 2015 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 <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sepol/module.h>
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/util.h>
+
+#ifdef __GNUC__
+#  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+#  define UNUSED(x) UNUSED_ ## x
+#endif
+
+FILE *out_file;
+
+#define STACK_SIZE 16
+#define DEFAULT_LEVEL "systemlow"
+#define DEFAULT_OBJECT "object_r"
+#define GEN_REQUIRE_ATTR "cil_gen_require"
+
+__attribute__ ((format(printf, 1, 2)))
+static void log_err(const char *fmt, ...)
+{
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(stderr, fmt, argptr) < 0) {
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+	if (fprintf(stderr, "\n") < 0) {
+		_exit(EXIT_FAILURE);
+	}
+}
+
+static void cil_indent(int indent)
+{
+	if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+}
+
+__attribute__ ((format(printf, 1, 2)))
+static void cil_printf(const char *fmt, ...) {
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(out_file, fmt, argptr) < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void cil_println(int indent, const char *fmt, ...)
+{
+	cil_indent(indent);
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(out_file, fmt, argptr) < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+	if (fprintf(out_file, "\n") < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+}
+
+static int get_line(char **start, char *end, char **line)
+{
+	int rc = 1;
+	char *p = NULL;
+	size_t len = 0;
+
+	*line = NULL;
+
+	for (p = *start; p < end && isspace(*p); p++);
+
+	*start = p;
+
+	for (len = 0; p < end && *p != '\n' && *p != '\0'; p++, len++);
+
+	if (len == 0) {
+		rc = 0;
+		goto exit;
+	}
+
+	*line = malloc(len+1);
+	if (*line == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	memcpy(*line, *start, len);
+	(*line)[len] = '\0';
+
+	*start = p;
+
+	return rc;
+
+exit:
+	*start = NULL;
+	return rc;
+}
+
+struct map_args {
+	struct policydb *pdb;
+	struct avrule_block *block;
+	struct stack *decl_stack;
+	int scope;
+	int indent;
+	int sym_index;
+};
+
+struct stack {
+	 void **stack;
+	 int pos;
+	 int size;
+};
+
+struct role_list_node {
+	char *role_name;
+	role_datum_t *role;
+};
+
+struct attr_list_node {
+	char *attribute;
+	int is_type;
+	union {
+		struct type_set *ts;
+		struct role_set *rs;
+	} set;
+};
+
+struct list_node {
+	void *data;
+	struct list_node *next;
+};
+
+struct list {
+	struct list_node *head;
+};
+
+/* A linked list of all roles stored in the pdb
+ * which is iterated to determine types associated
+ * with each role when printing role_type statements
+ */
+static struct list *role_list;
+
+static void list_destroy(struct list **list)
+{
+	struct list_node *curr = (*list)->head;
+	struct list_node *tmp;
+
+	while (curr != NULL) {
+		tmp = curr->next;
+		free(curr);
+		curr = tmp;
+	}
+
+	free(*list);
+	*list = NULL;
+}
+
+static void role_list_destroy(void)
+{
+	struct list_node *curr = role_list->head;
+
+	while (curr != NULL) {
+		free(curr->data);
+		curr->data = NULL;
+		curr = curr->next;
+	}
+
+	list_destroy(&role_list);
+}
+
+static void attr_list_destroy(struct list **attr_list)
+{
+	if (attr_list == NULL || *attr_list == NULL) {
+		return;
+	}
+
+	struct list_node *curr = (*attr_list)->head;
+	struct attr_list_node *attr;
+
+	while (curr != NULL) {
+		attr = curr->data;
+		if (attr != NULL) {
+			free(attr->attribute);
+		}
+
+		free(curr->data);
+		curr->data = NULL;
+		curr = curr->next;
+	}
+
+	list_destroy(attr_list);
+}
+
+static int list_init(struct list **list)
+{
+	int rc = -1;
+	struct list *l = calloc(1, sizeof(*l));
+	if (l == NULL) {
+		goto exit;
+	}
+
+	*list = l;
+
+	return 0;
+
+exit:
+	list_destroy(&l);
+	return rc;
+}
+
+static int list_prepend(struct list *list, void *data)
+{
+	int rc = -1;
+	struct list_node *node = calloc(1, sizeof(*node));
+	if (node == NULL) {
+		goto exit;
+	}
+
+	node->data = data;
+	node->next = list->head;
+	list->head = node;
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int roles_gather_map(char *key, void *data, void *args)
+{
+	struct role_list_node *role_node;
+	role_datum_t *role = data;
+	int rc = -1;
+
+	role_node = calloc(1, sizeof(*role_node));
+	if (role_node == NULL) {
+		return rc;
+	}
+
+	role_node->role_name = key;
+	role_node->role = role;
+
+	rc = list_prepend((struct list *)args, role_node);
+	return rc;
+}
+
+static int role_list_create(hashtab_t roles_tab)
+{
+	int rc = -1;
+
+	rc = list_init(&role_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = hashtab_map(roles_tab, roles_gather_map, role_list);
+
+exit:
+	return rc;
+}
+
+// array of lists, where each list contains all the aliases defined in the scope at index i
+static struct list **typealias_lists;
+static uint32_t typealias_lists_len;
+
+static int typealiases_gather_map(char *key, void *data, void *arg)
+{
+	int rc = -1;
+	struct type_datum *type = data;
+	struct policydb *pdb = arg;
+	struct scope_datum *scope;
+	uint32_t i;
+	uint32_t scope_id;
+
+	if (type->primary != 1) {
+		scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
+		if (scope == NULL) {
+			return -1;
+		}
+
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			scope_id = scope->decl_ids[i];
+			if (typealias_lists[scope_id] == NULL) {
+				rc = list_init(&typealias_lists[scope_id]);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+			list_prepend(typealias_lists[scope_id], key);
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static void typealias_list_destroy(void)
+{
+	uint32_t i;
+	for (i = 0; i < typealias_lists_len; i++) {
+		if (typealias_lists[i] != NULL) {
+			list_destroy(&typealias_lists[i]);
+		}
+	}
+	typealias_lists_len = 0;
+	free(typealias_lists);
+	typealias_lists = NULL;
+}
+
+static int typealias_list_create(struct policydb *pdb)
+{
+	uint32_t max_decl_id = 0;
+	struct avrule_decl *decl;
+	struct avrule_block *block;
+	uint32_t rc = -1;
+
+	for (block = pdb->global; block != NULL; block = block->next) {
+		decl = block->branch_list;
+		if (decl->decl_id > max_decl_id) {
+			max_decl_id = decl->decl_id;
+		}
+	}
+
+	typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
+	typealias_lists_len = max_decl_id + 1;
+
+	rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	typealias_list_destroy();
+
+	return rc;
+}
+
+
+static int stack_destroy(struct stack **stack)
+{
+	if (stack == NULL || *stack == NULL) {
+		return 0;
+	}
+
+	free((*stack)->stack);
+	free(*stack);
+	*stack = NULL;
+
+	return 0;
+}
+
+static int stack_init(struct stack **stack)
+{
+	int rc = -1;
+	struct stack *s = calloc(1, sizeof(*s));
+	if (s == NULL) {
+		goto exit;
+	}
+
+	s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
+	if (s->stack == NULL) {
+		goto exit;
+	}
+
+	s->pos = -1;
+	s->size = STACK_SIZE;
+
+	*stack = s;
+
+	return 0;
+
+exit:
+	stack_destroy(&s);
+	return rc;
+}
+
+static int stack_push(struct stack *stack, void *ptr)
+{
+	int rc = -1;
+	void *new_stack;
+
+	if (stack->pos + 1 == stack->size) {
+		new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
+		if (new_stack == NULL) {
+			goto exit;
+		}
+		stack->stack = new_stack;
+		stack->size *= 2;
+	}
+
+	stack->pos++;
+	stack->stack[stack->pos] = ptr;
+
+	rc = 0;
+exit:
+	return rc;
+}
+
+static void *stack_pop(struct stack *stack)
+{
+	if (stack->pos == -1) {
+		return NULL;
+	}
+
+	stack->pos--;
+	return stack->stack[stack->pos + 1];
+}
+
+static void *stack_peek(struct stack *stack)
+{
+	if (stack->pos == -1) {
+		return NULL;
+	}
+
+	return stack->stack[stack->pos];
+}
+
+static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
+{
+	int i;
+	uint32_t j;
+	struct avrule_decl *decl;
+	struct scope_datum *scope;
+
+	scope = hashtab_search(pdb->scope[symbol_type].table, id);
+	if (scope == NULL) {
+		return 0;
+	}
+
+	for (i = start; i >= 0; i--) {
+		decl = decl_stack->stack[i];
+
+		for (j = 0; j < scope->decl_ids_len; j++) {
+			if (scope->decl_ids[j] == decl->decl_id) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+	int start = decl_stack->pos - 1;
+
+	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+	int start = decl_stack->pos;
+
+	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
+{
+	struct mls_semantic_cat *cat;
+
+	cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
+
+	if (level->cat != NULL) {
+		cil_printf("(");
+	}
+
+	for (cat = level->cat; cat != NULL; cat = cat->next) {
+		if (cat->low == cat->high) {
+			cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
+		} else {
+			cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
+		}
+
+		if (cat->next != NULL) {
+			cil_printf(" ");
+		}
+	}
+
+	if (level->cat != NULL) {
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	return 0;
+}
+
+static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
+{
+	int rc = -1;
+	const char *rule;
+	const struct class_perm_node *classperm;
+	char *perms;
+
+	switch (type) {
+	case AVRULE_ALLOWED:
+		rule = "allow";
+		break;
+	case AVRULE_AUDITALLOW:
+		rule = "auditallow";
+		break;
+	case AVRULE_AUDITDENY:
+		rule = "auditdenty";
+		break;
+	case AVRULE_DONTAUDIT:
+		rule = "dontaudit";
+		break;
+	case AVRULE_NEVERALLOW:
+		rule = "neverallow";
+		break;
+	case AVRULE_TRANSITION:
+		rule = "typetransition";
+		break;
+	case AVRULE_MEMBER:
+		rule = "typemember";
+		break;
+	case AVRULE_CHANGE:
+		rule = "typechange";
+		break;
+	default:
+		log_err("Unknown avrule type: %i", type);
+		rc = -1;
+		goto exit;
+	}
+
+	for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
+		if (type & AVRULE_AV) {
+			perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
+			if (perms == NULL) {
+				log_err("Failed to generate permission string");
+				rc = -1;
+				goto exit;
+			}
+			cil_println(indent, "(%s %s %s (%s (%s)))",
+					rule, src, tgt,
+					pdb->p_class_val_to_name[classperm->tclass - 1],
+					perms + 1);
+		} else {
+			cil_println(indent, "(%s %s %s %s %s)",
+					rule, src, tgt,
+					pdb->p_class_val_to_name[classperm->tclass - 1],
+					pdb->p_type_val_to_name[classperm->data - 1]);
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int num_digits(int n)
+{
+	int num = 1;
+	while (n >= 10) {
+		n /= 10;
+		num++;
+	}
+	return num;
+}
+
+static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
+{
+	static unsigned int num_attrs = 0;
+	int rc = -1;
+	int len, rlen;
+	const char *attr_infix;
+	char *attr;
+
+	num_attrs++;
+
+	if (is_type) {
+		attr_infix = "_typeattr_";
+	} else {
+		attr_infix = "_roleattr_";
+	}
+
+	len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
+	attr = malloc(len);
+	if (attr == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+	rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
+	if (rlen < 0 || rlen >= len) {
+		log_err("Failed to generate attribute name");
+		rc = -1;
+		goto exit;
+	}
+
+	*names = malloc(sizeof(**names));
+	if (*names == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+
+	*names[0] = attr;
+	*num_names = 1;
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
+{
+	// CIL doesn't support anonymous positive/negative/complemented sets.  So
+	// instead we create a CIL type/roleattributeset that matches the set. If
+	// the set has a negative set, then convert it to is (P & !N), where P is
+	// the list of members in the positive set , and N is the list of members
+	// in the negative set. Additonally, if the set is complemented, then wrap
+	// the whole thing with a negation.
+
+	int rc = 0;
+	struct ebitmap_node *node;
+	unsigned int i;
+	char *statement;
+	int has_positive = pos && (ebitmap_cardinality(pos) > 0);
+	int has_negative = neg && (ebitmap_cardinality(neg) > 0);
+	char **val_to_name;
+
+	if (is_type) {
+		statement = "type";
+		val_to_name = pdb->p_type_val_to_name;
+	} else {
+		statement = "role";
+		val_to_name = pdb->p_role_val_to_name;
+	}
+
+	cil_println(indent, "(%sattribute %s)", statement, attr);
+	cil_indent(indent);
+	cil_printf("(%sattributeset %s ", statement, attr);
+
+	if (flags & TYPE_STAR) {
+		cil_printf("(all)");
+	}
+
+	if (flags & TYPE_COMP) {
+		cil_printf("(not ");
+	}
+
+	if (has_positive && has_negative) {
+		cil_printf("(and ");
+	}
+
+	if (has_positive) {
+		cil_printf("(");
+		ebitmap_for_each_bit(pos, node, i) {
+			if (!ebitmap_get_bit(pos, i)) {
+				continue;
+			}
+			cil_printf("%s ", val_to_name[i]);
+		}
+		cil_printf(") ");
+	}
+
+	if (has_negative) {
+		cil_printf("(not (");
+
+		ebitmap_for_each_bit(neg, node, i) {
+			if (!ebitmap_get_bit(neg, i)) {
+				continue;
+			}
+			cil_printf("%s ", val_to_name[i]);
+		}
+
+		cil_printf("))");
+	}
+
+	if (has_positive && has_negative) {
+		cil_printf(")");
+	}
+
+	if (flags & TYPE_COMP) {
+		cil_printf(")");
+	}
+
+	cil_printf(")\n");
+
+	return rc;
+}
+
+static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+	char **val_to_name = pdb->sym_val_to_name[type];
+
+	ebitmap_for_each_bit(map, node, i) {
+		if (!ebitmap_get_bit(map, i)) {
+			continue;
+		}
+		cil_printf("%s ", val_to_name[i]);
+	}
+
+	return 0;
+}
+
+static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+	uint32_t num = 0;
+	uint32_t max = 8;
+	char **name_arr = NULL;
+
+	name_arr = malloc(sizeof(*name_arr) * max);
+	if (name_arr == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	ebitmap_for_each_bit(&map, node, i) {
+		if (!ebitmap_get_bit(&map, i)) {
+			continue;
+		}
+
+		if (num + 1 == max) {
+			max *= 2;
+			name_arr = realloc(name_arr, sizeof(*name_arr) * max);
+			if (name_arr == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+		}
+
+		name_arr[num] = strdup(vals_to_names[i]);
+		if (name_arr[num] == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+		num++;
+	}
+
+	*names = name_arr;
+	*num_names = num;
+
+	return 0;
+
+exit:
+	for (i = 0; i < num; i++) {
+		free(name_arr[i]);
+	}
+	free(name_arr);
+	return rc;
+}
+
+static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
+{
+	struct attr_list_node *attr_list_node = NULL;
+	int rc = -1;
+
+	attr_list_node = calloc(1, sizeof(*attr_list_node));
+	if (attr_list_node == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = list_prepend(attr_list, attr_list_node);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	attr_list_node->attribute = strdup(attribute);
+	if (attr_list_node->attribute == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	attr_list_node->is_type = is_type;
+	if (is_type) {
+		attr_list_node->set.ts = set;
+	} else {
+		attr_list_node->set.rs = set;
+	}
+
+	return rc;
+
+exit:
+	if (attr_list_node != NULL) {
+		free(attr_list_node->attribute);
+	}
+	free(attr_list_node);
+	return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+	int rc = -1;
+	if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
+		rc = set_to_cil_attr(pdb, 1, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		*generated_attribute = *names[0];
+	} else {
+		rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+	int rc = -1;
+	if (rs->flags != 0) {
+		rc = set_to_cil_attr(pdb, 0, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		*generated_attribute = *names[0];
+	} else {
+		rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+	int rc = -1;
+	char *generated_attribute = NULL;
+	*num_type_names = 0;
+
+	rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (generated_attribute == NULL) {
+		goto exit;
+	}
+
+	if (attr_list == NULL) {
+		rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+		if (rc != 0) {
+			goto exit;
+		}
+	} else {
+		rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+	int rc = -1;
+	char *generated_attribute = NULL;
+	*num_type_names = 0;
+
+	rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (generated_attribute == NULL) {
+		rc = 0;
+		goto exit;
+	}
+
+	if (attr_list == NULL) {
+		rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+		if (rc != 0) {
+			goto exit;
+		}
+	} else {
+		rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static void names_destroy(char ***names, uint32_t *num_names)
+{
+	char **arr = *names;
+	uint32_t num = *num_names;
+	uint32_t i;
+
+	for (i = 0; i < num; i++) {
+		free(arr[i]);
+		arr[i] = NULL;
+	}
+	free(arr);
+
+	*names = NULL;
+	*num_names = 0;
+}
+
+static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
+{
+	struct list_node *curr;
+	char **tnames = NULL;
+	uint32_t num_tnames, i;
+	struct role_list_node *role_node = NULL;
+	int rc;
+	struct type_set *ts;
+
+	curr = role_list->head;
+	for (curr = role_list->head; curr != NULL; curr = curr->next) {
+		role_node = curr->data;
+		if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
+			continue;
+		}
+
+		ts = &role_node->role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
+		if (rc != 0) {
+			goto exit;
+		}
+		for (i = 0; i < num_tnames; i++) {
+			if (!strcmp(type_name, tnames[i])) {
+				cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
+			}
+		}
+		names_destroy(&tnames, &num_tnames);
+	}
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+
+static int name_list_to_string(char **names, int num_names, char **string)
+{
+	// create a space separated string of the names
+	int rc = -1;
+	int len = 0;
+	int i;
+	char *str;
+	char *strpos;
+	int name_len;
+	int rlen;
+
+	for (i = 0; i < num_names; i++) {
+		len += strlen(names[i]);
+	}
+
+	// add spaces + null terminator
+	len += (num_names - 1) + 1;
+
+	str = malloc(len);
+	if (str == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	strpos = str;
+
+	for (i = 0; i < num_names; i++) {
+		name_len = strlen(names[i]);
+		rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
+		if (rlen < 0 || rlen >= len) {
+			log_err("Failed to generate name list");
+			rc = -1;
+			goto exit;
+		}
+
+		if (i < num_names - 1) {
+			strpos[name_len] = ' ';
+		}
+		strpos += name_len + 1;
+	}
+
+	*string = str;
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
+{
+	int rc = -1;
+	struct avrule *avrule;
+	char **snames = NULL;
+	char **tnames = NULL;
+	uint32_t num_snames;
+	uint32_t num_tnames;
+	uint32_t s;
+	uint32_t t;
+	struct type_set *ts;
+
+	for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
+		if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) {
+			cil_println(0, ";;* lmx %lu %s\n",avrule->source_line, avrule->source_filename);
+		}
+
+		ts = &avrule->stypes;
+		rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &avrule->ttypes;
+		rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (s = 0; s < num_snames; s++) {
+			for (t = 0; t < num_tnames; t++) {
+				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+
+			if (avrule->flags & RULE_SELF) {
+				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+		}
+
+		names_destroy(&snames, &num_snames);
+		names_destroy(&tnames, &num_tnames);
+
+		if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) {
+			cil_println(0, ";;* lme\n");
+		}
+	}
+
+	return 0;
+
+exit:
+	names_destroy(&snames, &num_snames);
+	names_destroy(&tnames, &num_tnames);
+
+	return rc;
+}
+
+static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
+{
+	int rc = -1;
+	struct cond_expr *curr;
+	struct stack *stack = NULL;
+	int len = 0;
+	int rlen;
+	char *new_val = NULL;
+	char *val1 = NULL;
+	char *val2 = NULL;
+	int num_params;
+	const char *op;
+	const char *fmt_str;
+	const char *type;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		log_err("Out of memory");
+		goto exit;
+	}
+
+	for (curr = cond_expr; curr != NULL; curr = curr->next) {
+		if (curr->expr_type == COND_BOOL) {
+			val1 = pdb->p_bool_val_to_name[curr->bool - 1];
+			// length of boolean + 2 parens + null terminator
+			len = strlen(val1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+			rlen = snprintf(new_val, len, "(%s)", val1);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate conditional expression");
+				rc = -1;
+				goto exit;
+			}
+			num_params = 0;
+		} else {
+			switch(curr->expr_type) {
+			case COND_NOT:	op = "not";	break;
+			case COND_OR:	op = "or";	break;
+			case COND_AND:	op = "and";	break;
+			case COND_XOR:	op = "xor";	break;
+			case COND_EQ:	op = "eq";	break;
+			case COND_NEQ:	op = "neq";	break;
+			default:
+				rc = -1;
+				goto exit;
+			}
+
+			num_params = curr->expr_type == COND_NOT ? 1 : 2;
+
+			if (num_params == 1) {
+				val1 = stack_pop(stack);
+				val2 = strdup("");
+				if (val2 == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				fmt_str = "(%s %s)";
+			} else {
+				val2 = stack_pop(stack);
+				val1 = stack_pop(stack);
+				fmt_str = "(%s %s %s)";
+			}
+
+			if (val1 == NULL || val2 == NULL) {
+				log_err("Invalid conditional expression");
+				rc = -1;
+				goto exit;
+			}
+
+			// length = length of parameters +
+			//          length of operator +
+			//          1 space preceeding each parameter +
+			//          2 parens around the whole expression
+			//          + null terminator
+			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+
+			// although we always supply val2 and there isn't always a 2nd
+			// value, it should only be used when there are actually two values
+			// in the format strings
+			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate conditional expression");
+				rc = -1;
+				goto exit;
+			}
+
+			free(val1);
+			free(val2);
+			val1 = NULL;
+			val2 = NULL;
+		}
+
+		rc = stack_push(stack, new_val);
+		if (rc != 0) {
+			log_err("Out of memory");
+			goto exit;
+		}
+		new_val = NULL;
+	}
+
+	if (flags & COND_NODE_FLAGS_TUNABLE) {
+		type = "tunableif";
+	} else {
+		type = "booleanif";
+	}
+
+	val1 = stack_pop(stack);
+	if (val1 == NULL || stack_peek(stack) != NULL) {
+		log_err("Invalid conditional expression");
+		rc = -1;
+		goto exit;
+	}
+
+	cil_println(indent, "(%s %s", type, val1);
+	free(val1);
+	val1 = NULL;
+
+	rc = 0;
+
+exit:
+	free(new_val);
+	free(val1);
+	free(val2);
+	while ((val1 = stack_pop(stack)) != NULL) {
+		free(val1);
+	}
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
+{
+	struct list_node *curr;
+	struct attr_list_node *attr_list_node;
+	int rc = 0;
+	struct type_set *ts;
+	struct role_set *rs;
+	char *generated_attribute;
+
+	for (curr = attr_list->head; curr != NULL; curr = curr->next) {
+		attr_list_node = curr->data;
+		generated_attribute = attr_list_node->attribute;
+		if (generated_attribute == NULL) {
+			return -1;
+		}
+
+		if (attr_list_node->is_type) {
+			ts = attr_list_node->set.ts;
+			rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+			if (rc != 0) {
+				return rc;
+			}
+		} else {
+			rs = attr_list_node->set.rs;
+			rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+			if (rc != 0) {
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
+{
+	int rc = -1;
+	struct cond_node *cond;
+	struct list *attr_list;
+
+	rc = list_init(&attr_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (cond = cond_list; cond != NULL; cond = cond->next) {
+
+		rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		if (cond->avtrue_list != NULL) {
+			cil_println(indent + 1, "(true");
+			rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
+			if (rc != 0) {
+				goto exit;
+			}
+			cil_println(indent + 1, ")");
+		}
+
+		if (cond->avfalse_list != NULL) {
+			cil_println(indent + 1, "(false");
+			rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
+			if (rc != 0) {
+				goto exit;
+			}
+			cil_println(indent + 1, ")");
+		}
+
+		cil_println(indent, ")");
+	}
+
+	rc = cil_print_attr_list(indent, pdb, attr_list);
+
+exit:
+	attr_list_destroy(&attr_list);
+	return rc;
+}
+
+static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
+{
+	int rc = -1;
+	struct role_trans_rule *rule;
+	char **role_names = NULL;
+	uint32_t num_role_names = 0;
+	char **type_names = NULL;
+	uint32_t num_type_names = 0;
+	uint32_t type;
+	uint32_t role;
+	uint32_t i;
+	struct ebitmap_node *node;
+	struct type_set *ts;
+	struct role_set *rs;
+
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		rs = &rule->roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (role = 0; role < num_role_names; role++) {
+			for (type = 0; type < num_type_names; type++) {
+				ebitmap_for_each_bit(&rule->classes, node, i) {
+					if (!ebitmap_get_bit(&rule->classes, i)) {
+						continue;
+					}
+					cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
+					                                                    type_names[type],
+					                                                    pdb->p_class_val_to_name[i],
+					                                                    pdb->p_role_val_to_name[rule->new_role - 1]);
+				}
+			}
+		}
+
+		names_destroy(&role_names, &num_role_names);
+		names_destroy(&type_names, &num_type_names);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&role_names, &num_role_names);
+	names_destroy(&type_names, &num_type_names);
+
+	return rc;
+}
+
+static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
+{
+	int rc = -1;
+	struct role_allow_rule *rule;
+	char **roles = NULL;
+	uint32_t num_roles = 0;
+	char **new_roles = NULL;
+	uint32_t num_new_roles = 0;
+	uint32_t i;
+	uint32_t j;
+	struct role_set *rs;
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		rs = &rule->roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rs = &rule->new_roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (i = 0; i < num_roles; i++) {
+			for (j = 0; j < num_new_roles; j++) {
+				cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
+			}
+		}
+
+		names_destroy(&roles, &num_roles);
+		names_destroy(&new_roles, &num_new_roles);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&roles, &num_roles);
+	names_destroy(&new_roles, &num_new_roles);
+
+	return rc;
+}
+
+static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
+{
+	int rc = -1;
+	struct range_trans_rule *rule;
+	char **stypes = NULL;
+	uint32_t num_stypes = 0;
+	char **ttypes = NULL;
+	uint32_t num_ttypes = 0;
+	struct ebitmap_node *node;
+	uint32_t i;
+	uint32_t stype;
+	uint32_t ttype;
+	struct type_set *ts;
+
+	if (!pdb->mls) {
+		return 0;
+	}
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		ts = &rule->stypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->ttypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (stype = 0; stype < num_stypes; stype++) {
+			for (ttype = 0; ttype < num_ttypes; ttype++) {
+				ebitmap_for_each_bit(&rule->tclasses, node, i) {
+					if (!ebitmap_get_bit(&rule->tclasses, i)) {
+						continue;
+					}
+
+					cil_indent(indent);
+					cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
+
+					cil_printf("(");
+
+					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
+					if (rc != 0) {
+						goto exit;
+					}
+
+					cil_printf(" ");
+
+					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
+					if (rc != 0) {
+						goto exit;
+					}
+
+					cil_printf("))\n");
+				}
+
+			}
+		}
+
+		names_destroy(&stypes, &num_stypes);
+		names_destroy(&ttypes, &num_ttypes);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&stypes, &num_stypes);
+	names_destroy(&ttypes, &num_ttypes);
+
+	return rc;
+}
+
+static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
+{
+	int rc = -1;
+	char **stypes = NULL;
+	uint32_t num_stypes = 0;
+	char **ttypes = NULL;
+	uint32_t num_ttypes = 0;
+	uint32_t stype;
+	uint32_t ttype;
+	struct type_set *ts;
+
+	struct filename_trans_rule *rule;
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		ts = &rule->stypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->ttypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (stype = 0; stype < num_stypes; stype++) {
+			for (ttype = 0; ttype < num_ttypes; ttype++) {
+				cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
+				                                                       ttypes[ttype],
+				                                                       pdb->p_class_val_to_name[rule->tclass - 1],
+				                                                       rule->name,
+				                                                       pdb->p_type_val_to_name[rule->otype - 1]);
+			}
+		}
+
+		names_destroy(&stypes, &num_stypes);
+		names_destroy(&ttypes, &num_ttypes);
+	}
+
+	rc = 0;
+exit:
+	names_destroy(&stypes, &num_stypes);
+	names_destroy(&ttypes, &num_ttypes);
+
+	return rc;
+}
+
+struct class_perm_datum {
+	char *name;
+	uint32_t val;
+};
+
+struct class_perm_array {
+	struct class_perm_datum *perms;
+	uint32_t count;
+};
+
+static int class_perm_to_array(char *key, void *data, void *args)
+{
+	struct class_perm_array *arr = args;
+	struct perm_datum *datum = data;
+	arr->perms[arr->count].name = key;
+	arr->perms[arr->count].val = datum->s.value;
+	arr->count++;
+
+	return 0;
+}
+
+static int class_perm_cmp(const void *a, const void *b)
+{
+	const struct class_perm_datum *aa = a;
+	const struct class_perm_datum *bb = b;
+
+	return aa->val - bb->val;
+}
+
+static int common_to_cil(char *key, void *data, void *UNUSED(arg))
+{
+	int rc = -1;
+	struct common_datum *common = data;
+	struct class_perm_array arr;
+	uint32_t i;
+
+	arr.count = 0;
+	arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
+	rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+	cil_printf("(common %s (", key);
+	for (i = 0; i < arr.count; i++) {
+		cil_printf("%s ", arr.perms[i].name);
+	}
+	cil_printf("))\n");
+
+	rc = 0;
+
+exit:
+	free(arr.perms);
+	return rc;
+}
+
+
+static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
+{
+	int rc = -1;
+	struct constraint_expr *expr;
+	struct stack *stack = NULL;
+	int len = 0;
+	int rlen;
+	char *new_val = NULL;
+	char *val1 = NULL;
+	char *val2 = NULL;
+	uint32_t num_params;
+	const char *op;
+	const char *fmt_str;
+	const char *attr1;
+	const char *attr2;
+	char *names;
+	char **name_list = NULL;
+	uint32_t num_names = 0;
+	struct type_set *ts;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (expr = exprs; expr != NULL; expr = expr->next) {
+		if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
+			switch (expr->op) {
+			case CEXPR_EQ:      op = "eq";     break;
+			case CEXPR_NEQ:     op = "neq";    break;
+			case CEXPR_DOM:     op = "dom";    break;
+			case CEXPR_DOMBY:   op = "domby";  break;
+			case CEXPR_INCOMP:  op = "incomp"; break;
+			default:
+				log_err("Unknown constraint operator type: %i", expr->op);
+				rc = -1;
+				goto exit;
+			}
+
+			switch (expr->attr) {
+			case CEXPR_USER:                 attr1 = "u1"; attr2 = "u2"; break;
+			case CEXPR_USER | CEXPR_TARGET:  attr1 = "u2"; attr2 = "";   break;
+			case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = "";   break;
+			case CEXPR_ROLE:                 attr1 = "r1"; attr2 = "r2"; break;
+			case CEXPR_ROLE | CEXPR_TARGET:  attr1 = "r2"; attr2 = "";   break;
+			case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = "";   break;
+			case CEXPR_TYPE:                 attr1 = "t1"; attr2 = "";   break;
+			case CEXPR_TYPE | CEXPR_TARGET:  attr1 = "t2"; attr2 = "";   break;
+			case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = "";   break;
+			case CEXPR_L1L2:                 attr1 = "l1"; attr2 = "l2"; break;
+			case CEXPR_L1H2:                 attr1 = "l1"; attr2 = "h2"; break;
+			case CEXPR_H1L2:                 attr1 = "h1"; attr2 = "l2"; break;
+			case CEXPR_H1H2:                 attr1 = "h1"; attr2 = "h2"; break;
+			case CEXPR_L1H1:                 attr1 = "l1"; attr2 = "h1"; break;
+			case CEXPR_L2H2:                 attr1 = "l2"; attr2 = "h2"; break;
+			default:
+				log_err("Unknown expression attribute type: %i", expr->attr);
+				rc = -1;
+				goto exit;
+			}
+
+			if (expr->expr_type == CEXPR_ATTR) {
+				// length of values/attrs + 2 separating spaces + 2 parens + null terminator
+				len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
+				new_val = malloc(len);
+				if (new_val == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
+				if (rlen < 0 || rlen >= len) {
+					log_err("Failed to generate constraint expression");
+					rc = -1;
+					goto exit;
+				}
+			} else {
+				if (expr->attr & CEXPR_TYPE) {
+					ts = expr->type_names;
+					rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				} else if (expr->attr & CEXPR_USER) {
+					rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				} else if (expr->attr & CEXPR_ROLE) {
+					rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				}
+				rc = name_list_to_string(name_list, num_names, &names);
+				if (rc != 0) {
+					goto exit;
+				}
+
+				// length of values/oper + 2 spaces + 2 parens + null terminator
+				len = strlen(op) + strlen(attr1) +  strlen(names) + 2 + 2 + 1;
+				new_val = malloc(len);
+				if (new_val == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
+				if (rlen < 0 || rlen >= len) {
+					log_err("Failed to generate constraint expression");
+					rc = -1;
+					goto exit;
+				}
+
+				names_destroy(&name_list, &num_names);
+				free(names);
+			}
+
+			num_params = 0;
+		} else {
+			switch (expr->expr_type) {
+			case CEXPR_NOT: op = "not"; break;
+			case CEXPR_AND: op = "and"; break;
+			case CEXPR_OR:  op = "or"; break;
+			default:
+				log_err("Unknown constraint expression type: %i", expr->expr_type);
+				rc = -1;
+				goto exit;
+			}
+
+			num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
+
+			if (num_params == 1) {
+				val1 = stack_pop(stack);
+				val2 = strdup("");
+				if (val2 == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				fmt_str = "(%s %s)";
+			} else {
+				val2 = stack_pop(stack);
+				val1 = stack_pop(stack);
+				fmt_str = "(%s %s %s)";
+			}
+
+			if (val1 == NULL || val2 == NULL) {
+				log_err("Invalid constraint expression");
+				rc = -1;
+				goto exit;
+			}
+
+			// length = length of parameters +
+			//          length of operator +
+			//          1 space preceeding each parameter +
+			//          2 parens around the whole expression
+			//          + null terminator
+			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+
+			// although we always supply val2 and there isn't always a 2nd
+			// value, it should only be used when there are actually two values
+			// in the format strings
+			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate constraint expression");
+				rc = -1;
+				goto exit;
+			}
+
+			free(val1);
+			free(val2);
+			val1 = NULL;
+			val2 = NULL;
+		}
+
+		rc = stack_push(stack, new_val);
+		if (rc != 0) {
+			log_err("Out of memory");
+			goto exit;
+		}
+
+		new_val = NULL;
+	}
+
+	new_val = stack_pop(stack);
+	if (new_val == NULL || stack_peek(stack) != NULL) {
+		log_err("Invalid constraint expression");
+		rc = -1;
+		goto exit;
+	}
+
+	*expr_string = new_val;
+	new_val = NULL;
+
+	rc = 0;
+
+exit:
+	names_destroy(&name_list, &num_names);
+
+	free(new_val);
+	free(val1);
+	free(val2);
+	while ((val1 = stack_pop(stack)) != NULL) {
+		free(val1);
+	}
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+
+static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
+{
+	int rc = -1;
+	struct constraint_node *node;
+	char *expr = NULL;
+	const char *mls;
+	char *perms;
+
+	mls = pdb->mls ? "mls" : "";
+
+	for (node = constraints; node != NULL; node = node->next) {
+
+		rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		if (is_constraint) {
+			perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
+			cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
+		} else {
+			cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
+		}
+
+		free(expr);
+		expr = NULL;
+	}
+
+	rc = 0;
+
+exit:
+	free(expr);
+	return rc;
+}
+
+static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct class_datum *class = datum;
+	const char *dflt;
+	struct class_perm_array arr;
+	uint32_t i;
+
+	if (scope == SCOPE_REQ) {
+		return 0;
+	}
+
+	arr.count = 0;
+	arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
+	rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+	cil_indent(indent);
+	cil_printf("(class %s (", key);
+	for (i = 0; i < arr.count; i++) {
+		cil_printf("%s ", arr.perms[i].name);
+	}
+	cil_printf("))\n");
+
+	if (class->comkey != NULL) {
+		cil_println(indent, "(classcommon %s %s)", key, class->comkey);
+	}
+
+	if (class->default_user != 0) {
+		switch (class->default_user) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default user value: %i", class->default_user);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultuser %s %s)", key, dflt);
+	}
+
+	if (class->default_role != 0) {
+		switch (class->default_role) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default role value: %i", class->default_role);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultrole %s %s)", key, dflt);
+	}
+
+	if (class->default_type != 0) {
+		switch (class->default_type) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default type value: %i", class->default_type);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaulttype %s %s)", key, dflt);
+	}
+
+	if (class->default_range != 0) {
+		switch (class->default_range) {
+		case DEFAULT_SOURCE_LOW:		dflt = "source low";	break;
+		case DEFAULT_SOURCE_HIGH:		dflt = "source high";	break;
+		case DEFAULT_SOURCE_LOW_HIGH:	dflt = "source low-high";	break;
+		case DEFAULT_TARGET_LOW:		dflt = "target low";	break;
+		case DEFAULT_TARGET_HIGH:		dflt = "target high";	break;
+		case DEFAULT_TARGET_LOW_HIGH:	dflt = "target low-high";	break;
+		default:
+			log_err("Unknown default range value: %i", class->default_range);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultrange %s %s)", key, dflt);
+
+	}
+
+	if (class->constraints != NULL) {
+		rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	if (class->validatetrans != NULL) {
+		rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	rc = 0;
+
+exit:
+	free(arr.perms);
+	return rc;
+}
+
+static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		return 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(classorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+}
+
+static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+	char **types = NULL;
+	uint32_t num_types = 0;
+	struct role_datum *role = datum;
+	struct type_set *ts;
+
+	if (scope == SCOPE_REQ) {
+		// if a role/roleattr is in the REQ scope, then it could cause an
+		// optional block to fail, even if it is never used. However in CIL,
+		// symbols must be used in order to cause an optional block to fail. So
+		// for symbols in the REQ scope, add them to a roleattribute as a way
+		// to 'use' them in the optional without affecting the resulting policy.
+		cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
+	}
+
+	switch (role->flavor) {
+	case ROLE_ROLE:
+		if (scope == SCOPE_DECL) {
+			// Only declare certain roles if we are reading a base module.
+			// These roles are defined in the base module and sometimes in
+			// other non-base modules. If we generated the roles regardless of
+			// the policy type, it would result in duplicate declarations,
+			// which isn't allowed in CIL. Patches have been made to refpolicy
+			// to remove these duplicate role declarations, but we need to be
+			// backwards compatable and support older policies. Since we know
+			// these roles are always declared in base, only print them when we
+			// see them in the base module. If the declarations appear in a
+			// non-base module, ignore their declarations.
+			//
+			// Note that this is a hack, and if a policy author does not define
+			// one of these roles in base, the declaration will not appeaer in
+			// the resulting policy, likely resulting in a compilation error in
+			// CIL.
+			//
+			// To make things more complicated, the auditadm_r and secadm_r
+			// roles could actually be in either the base module or a non-base
+			// module, or both. So we can't rely on this same behavior. So for
+			// these roles, don't declare them here, even if they are in a base
+			// or non-base module. Instead we will just declare them in the
+			// base module elsewhere.
+			int is_base_role = (!strcmp(key, "user_r") ||
+			                    !strcmp(key, "staff_r") ||
+			                    !strcmp(key, "sysadm_r") ||
+			                    !strcmp(key, "system_r") ||
+			                    !strcmp(key, "unconfined_r"));
+			int is_builtin_role = (!strcmp(key, "auditadm_r") ||
+			                       !strcmp(key, "secadm_r"));
+			if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) ||
+			    (!is_base_role && !is_builtin_role)) {
+				cil_println(indent, "(role %s)", key);
+			}
+		}
+
+		if (ebitmap_cardinality(&role->dominates) > 1) {
+			log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
+		}
+
+		ts = &role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (i = 0; i < num_types; i++) {
+			if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+				cil_println(indent, "(roletype %s %s)", key, types[i]);
+			}
+		}
+
+		if (role->bounds > 0) {
+			cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
+		}
+		break;
+
+	case ROLE_ATTRIB:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(roleattribute %s)", key);
+		}
+
+		if (ebitmap_cardinality(&role->roles) > 0) {
+			cil_indent(indent);
+			cil_printf("(roleattributeset %s (", key);
+			ebitmap_for_each_bit(&role->roles, node, i) {
+				if (!ebitmap_get_bit(&role->roles, i)) {
+					continue;
+				}
+				cil_printf("%s ", pdb->p_role_val_to_name[i]);
+			}
+			cil_printf("))\n");
+		}
+
+		ts = &role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+		if (rc != 0) {
+			goto exit;
+		}
+
+
+		for (i = 0; i < num_types; i++) {
+			if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+				cil_println(indent, "(roletype %s %s)", key, types[i]);
+			}
+		}
+
+		break;
+
+	default:
+		log_err("Unknown role type: %i", role->flavor);
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	names_destroy(&types, &num_types);
+
+	return rc;
+}
+
+static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct type_datum *type = datum;
+
+	if (scope == SCOPE_REQ) {
+		// if a type/typeattr is in the REQ scope, then it could cause an
+		// optional block to fail, even if it is never used. However in CIL,
+		// symbols must be used in order to cause an optional block to fail. So
+		// for symbols in the REQ scope, add them to a typeattribute as a way
+		// to 'use' them in the optional without affecting the resulting policy.
+		cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
+	}
+
+	rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	switch(type->flavor) {
+	case TYPE_TYPE:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(type %s)", key);
+			// object_r is implicit in checkmodule, but not with CIL,
+			// create it as part of base
+			cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
+		}
+
+		if (type->flags & TYPE_FLAGS_PERMISSIVE) {
+			cil_println(indent, "(typepermissive %s)", key);
+		}
+
+		if (type->bounds > 0) {
+			cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
+		}
+		break;
+	case TYPE_ATTRIB:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(typeattribute %s)", key);
+		}
+
+		if (ebitmap_cardinality(&type->types) > 0) {
+			cil_indent(indent);
+			cil_printf("(typeattributeset %s (", key);
+			ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
+			cil_printf("))\n");
+		}
+		break;
+	default:
+		log_err("Unknown flavor (%i) of type %s", type->flavor, key);
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct user_datum *user = datum;
+	struct ebitmap roles = user->roles.roles;
+	struct mls_semantic_level level = user->dfltlevel;
+	struct mls_semantic_range range = user->range;
+	struct ebitmap_node *node;
+	uint32_t i;
+	int sens_offset = 1;
+
+	if (scope == SCOPE_DECL) {
+		cil_println(indent, "(user %s)", key);
+		// object_r is implicit in checkmodule, but not with CIL, create it
+		// as part of base
+		cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
+	}
+
+	ebitmap_for_each_bit(&roles, node, i) {
+		if (!ebitmap_get_bit(&roles, i)) {
+			continue;
+		}
+		cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
+	}
+
+	if (block->flags & AVRULE_OPTIONAL) {
+		// sensitivites in user statements in optionals do not have the
+		// standard -1 offest
+		sens_offset = 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(userlevel %s ", key);
+	if (pdb->mls) {
+		semantic_level_to_cil(pdb, sens_offset, &level);
+	} else {
+		cil_printf(DEFAULT_LEVEL);
+	}
+	cil_printf(")\n");
+
+	cil_indent(indent);
+	cil_printf("(userrange %s (", key);
+	if (pdb->mls) {
+		semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
+		cil_printf(" ");
+		semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
+	} else {
+		cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
+	}
+	cil_printf("))\n");
+
+
+	return 0;
+}
+
+static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct cond_bool_datum *boolean = datum;
+	const char *type;
+
+	if (scope == SCOPE_DECL) {
+		if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
+			type = "tunable";
+		} else {
+			type = "boolean";
+		}
+
+		cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
+	}
+
+	return 0;
+}
+
+static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+	struct level_datum *level = datum;
+
+	if (scope == SCOPE_DECL) {
+		if (!level->isalias) {
+			cil_println(indent, "(sensitivity %s)", key);
+		} else {
+			cil_println(indent, "(sensitivityalias %s)", key);
+			cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
+		}
+	}
+
+	if (ebitmap_cardinality(&level->level->cat) > 0) {
+		cil_indent(indent);
+		cil_printf("(sensitivitycategory %s (", key);
+		ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
+		cil_printf("))\n");
+	}
+
+	return 0;
+}
+
+static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		return 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(sensitivityorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->p_sens_val_to_name[i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+}
+
+static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct cat_datum *cat = datum;
+
+	if (scope == SCOPE_REQ) {
+		return 0;
+	}
+
+	if (!cat->isalias) {
+		cil_println(indent, "(category %s)", key);
+	} else {
+		cil_println(indent, "(categoryalias %s)", key);
+		cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
+	}
+
+	return 0;
+}
+
+static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		rc = 0;
+		goto exit;
+	}
+
+	cil_indent(indent);
+	cil_printf("(categoryorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->p_cat_val_to_name[i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int polcaps_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	struct ebitmap *map;
+	struct ebitmap_node *node;
+	uint32_t i;
+	const char *name;
+
+	map = &pdb->policycaps;
+
+	ebitmap_for_each_bit(map, node, i) {
+		if (!ebitmap_get_bit(map, i)) {
+			continue;
+		}
+		name = sepol_polcap_getname(i);
+		if (name == NULL) {
+			log_err("Unknown policy capability id: %i", i);
+			rc = -1;
+			goto exit;
+		}
+
+		cil_println(0, "(policycap %s)", name);
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int level_to_cil(struct policydb *pdb, struct mls_level *level)
+{
+	struct ebitmap *map = &level->cat;
+
+	cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
+
+	if (ebitmap_cardinality(map) > 0) {
+		cil_printf("(");
+		ebitmap_to_cil(pdb, map, SYM_CATS);
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	return 0;
+}
+
+static int context_to_cil(struct policydb *pdb, struct context_struct *con)
+{
+	cil_printf("(%s %s %s (",
+		pdb->p_user_val_to_name[con->user - 1],
+		pdb->p_role_val_to_name[con->role - 1],
+		pdb->p_type_val_to_name[con->type - 1]);
+
+	if (pdb->mls) {
+		level_to_cil(pdb, &con->range.level[0]);
+		cil_printf(" ");
+		level_to_cil(pdb, &con->range.level[1]);
+	} else {
+		cil_printf(DEFAULT_LEVEL);
+		cil_printf(" ");
+		cil_printf(DEFAULT_LEVEL);
+	}
+
+	cil_printf("))");
+
+	return 0;
+}
+
+static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
+{
+	int rc = -1;
+
+	struct ocontext *isid;
+
+	struct sid_item {
+		const char *sid_key;
+		struct sid_item *next;
+	};
+
+	struct sid_item *head = NULL;
+	struct sid_item *item = NULL;
+
+	for (isid = isids; isid != NULL; isid = isid->next) {
+		cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
+		cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
+		context_to_cil(pdb, &isid->context[0]);
+		cil_printf(")\n");
+
+		// get the sid names in the correct order (reverse from the isids
+		// ocontext) for sidorder statement
+		item = malloc(sizeof(*item));
+		if (item == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+		item->sid_key = sid_to_string[isid->sid[0]];
+		item->next = head;
+		head = item;
+	}
+
+	if (head != NULL) {
+		cil_printf("(sidorder (");
+		for (item = head; item != NULL; item = item->next) {
+			cil_printf("%s ", item->sid_key);
+		}
+		cil_printf("))\n");
+	}
+
+	rc = 0;
+
+exit:
+	while(head) {
+		item = head;
+		head = item->next;
+		free(item);
+	}
+	return rc;
+}
+
+static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+	int rc = -1;
+
+	// initial sid names aren't actually stored in the pp files, need to a have
+	// a mapping, taken from the linux kernel
+	static const char *selinux_sid_to_string[] = {
+		"null",
+		"kernel",
+		"security",
+		"unlabeled",
+		"fs",
+		"file",
+		"file_labels",
+		"init",
+		"any_socket",
+		"port",
+		"netif",
+		"netmsg",
+		"node",
+		"igmp_packet",
+		"icmp_socket",
+		"tcp_socket",
+		"sysctl_modprobe",
+		"sysctl",
+		"sysctl_fs",
+		"sysctl_kernel",
+		"sysctl_net",
+		"sysctl_net_unix",
+		"sysctl_vm",
+		"sysctl_dev",
+		"kmod",
+		"policy",
+		"scmp_packet",
+		"devnull",
+		NULL
+	};
+
+	rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
+{
+	if (fss != NULL) {
+		log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
+	}
+
+	return 0;
+}
+
+static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
+{
+	int rc = -1;
+	struct ocontext *portcon;
+	const char *protocol;
+	uint16_t high;
+	uint16_t low;
+
+	for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
+
+		switch (portcon->u.port.protocol) {
+		case IPPROTO_TCP: protocol = "tcp"; break;
+		case IPPROTO_UDP: protocol = "udp"; break;
+		case IPPROTO_DCCP: protocol = "dccp"; break;
+		default:
+			log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
+			rc = -1;
+			goto exit;
+		}
+
+		low = portcon->u.port.low_port;
+		high = portcon->u.port.high_port;
+
+		if (low == high) {
+			cil_printf("(portcon %s %i ", protocol, low);
+		} else {
+			cil_printf("(portcon %s (%i %i) ", protocol, low, high);
+		}
+
+		context_to_cil(pdb, &portcon->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
+{
+	struct ocontext *netif;
+
+	for (netif = netifs; netif != NULL; netif = netif->next) {
+		cil_printf("(netifcon %s ", netif->u.name);
+		context_to_cil(pdb, &netif->context[0]);
+
+		cil_printf(" ");
+		context_to_cil(pdb, &netif->context[1]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+	int rc = -1;
+	struct ocontext *node;
+	char addr[INET_ADDRSTRLEN];
+	char mask[INET_ADDRSTRLEN];
+
+	for (node = nodes; node != NULL; node = node->next) {
+		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon address is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon mask is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(nodecon %s %s ", addr, mask);
+
+		context_to_cil(pdb, &node->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+	int rc = -1;
+	struct ocontext *node;
+	char addr[INET6_ADDRSTRLEN];
+	char mask[INET6_ADDRSTRLEN];
+
+	for (node = nodes; node != NULL; node = node->next) {
+		if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon address is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon mask is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(nodecon %s %s ", addr, mask);
+
+		context_to_cil(pdb, &node->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
+{
+	int rc = -1;
+	struct ocontext *fsuse;
+	const char *behavior;
+
+
+	for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
+		switch (fsuse->v.behavior) {
+		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
+		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
+		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
+		default:
+			log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
+
+		context_to_cil(pdb, &fsuse->context[0]);
+
+		cil_printf(")\n");
+
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+	int rc = -1;
+
+	// initial sid names aren't actually stored in the pp files, need to a have
+	// a mapping, taken from the xen kernel
+	static const char *xen_sid_to_string[] = {
+		"null",
+		"xen",
+		"dom0",
+		"domio",
+		"domxen",
+		"unlabeled",
+		"security",
+		"ioport",
+		"iomem",
+		"irq",
+		"device",
+		NULL,
+	};
+
+	rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
+{
+	struct ocontext *pirq;
+
+	for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
+		cil_printf("(pirqcon %i ", pirq->u.pirq);
+		context_to_cil(pdb, &pirq->context[0]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
+{
+	struct ocontext *ioport;
+	uint32_t low;
+	uint32_t high;
+
+	for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
+		low = ioport->u.ioport.low_ioport;
+		high = ioport->u.ioport.high_ioport;
+
+		if (low == high) {
+			cil_printf("(ioportcon %i ", low);
+		} else {
+			cil_printf("(ioportcon (%i %i) ", low, high);
+		}
+
+		context_to_cil(pdb, &ioport->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
+{
+	struct ocontext *iomem;
+	uint64_t low;
+	uint64_t high;
+
+	for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
+		low = iomem->u.iomem.low_iomem;
+		high = iomem->u.iomem.high_iomem;
+
+		if (low == high) {
+			cil_printf("(iomemcon %#lX ", (unsigned long)low);
+		} else {
+			cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
+		}
+
+		context_to_cil(pdb, &iomem->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
+{
+	struct ocontext *pcid;
+
+	for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
+		cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
+		context_to_cil(pdb, &pcid->context[0]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontexts_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	int ocon;
+
+	static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
+	static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+		ocontext_selinux_isid_to_cil,
+		ocontext_selinux_fs_to_cil,
+		ocontext_selinux_port_to_cil,
+		ocontext_selinux_netif_to_cil,
+		ocontext_selinux_node_to_cil,
+		ocontext_selinux_fsuse_to_cil,
+		ocontext_selinux_node6_to_cil,
+	};
+	static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+		ocontext_xen_isid_to_cil,
+		ocontext_xen_pirq_to_cil,
+		ocontext_xen_ioport_to_cil,
+		ocontext_xen_iomem_to_cil,
+		ocontext_xen_pcidevice_to_cil,
+		NULL,
+		NULL,
+	};
+
+	switch (pdb->target_platform) {
+	case SEPOL_TARGET_SELINUX:
+		ocon_funcs = ocon_selinux_funcs;
+		break;
+	case SEPOL_TARGET_XEN:
+		ocon_funcs = ocon_xen_funcs;
+		break;
+	default:
+		log_err("Unknown target platform: %i", pdb->target_platform);
+		rc = -1;
+		goto exit;
+	}
+
+	for (ocon = 0; ocon < OCON_NUM; ocon++) {
+		if (ocon_funcs[ocon] != NULL) {
+			rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int genfscon_to_cil(struct policydb *pdb)
+{
+	struct genfs *genfs;
+	struct ocontext *ocon;
+
+	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
+		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
+			cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
+			context_to_cil(pdb, &ocon->context[0]);
+			cil_printf(")\n");
+		}
+	}
+
+	return 0;
+}
+
+static int level_string_to_cil(char *levelstr)
+{
+	int rc = -1;
+	char *sens = NULL;
+	char *cats = NULL;
+	int matched;
+	char *saveptr = NULL;
+	char *token = NULL;
+	char *ranged = NULL;
+
+	matched = tokenize(levelstr, ':', 2, &sens, &cats);
+	if (matched < 1 || matched > 2) {
+		log_err("Invalid level: %s", levelstr);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_printf("(%s", sens);
+
+	if (matched == 2) {
+		cil_printf("(");
+		token = strtok_r(cats, ",", &saveptr);
+		while (token != NULL) {
+			ranged = strchr(token, '.');
+			if (ranged == NULL) {
+				cil_printf("%s ", token);
+			} else {
+				*ranged = '\0';
+				cil_printf("(range %s %s) ", token, ranged + 1);
+			}
+			token = strtok_r(NULL, ",", &saveptr);
+		}
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	rc = 0;
+exit:
+	free(sens);
+	free(cats);
+	return rc;
+}
+
+static int level_range_string_to_cil(char *levelrangestr)
+{
+	char *ranged = NULL;
+	char *low;
+	char *high;
+
+	ranged = strchr(levelrangestr, '-');
+	if (ranged == NULL) {
+		low = high = levelrangestr;
+	} else {
+		*ranged = '\0';
+		low = levelrangestr;
+		high = ranged + 1;
+	}
+
+	level_string_to_cil(low);
+	cil_printf(" ");
+	level_string_to_cil(high);
+
+	return 0;
+}
+
+static int context_string_to_cil(char *contextstr)
+{
+	int rc = -1;
+	int matched;
+	char *user = NULL;
+	char *role = NULL;
+	char *type = NULL;
+	char *level = NULL;
+
+	matched = tokenize(contextstr, ':', 4, &user, &role, &type, &level);
+	if (matched < 3 || matched > 4) {
+		log_err("Invalid context: %s", contextstr);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_printf("(%s %s %s (", user, role, type);
+
+	if (matched == 3) {
+		cil_printf(DEFAULT_LEVEL);
+		cil_printf(" ");
+		cil_printf(DEFAULT_LEVEL);
+	} else {
+		level_range_string_to_cil(level);
+	}
+
+	cil_printf("))");
+
+	rc = 0;
+
+exit:
+	free(user);
+	free(role);
+	free(type);
+	free(level);
+
+	return rc;
+}
+
+static int seusers_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	char *seusers = sepol_module_package_get_seusers(mod_pkg);
+	size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
+	char *cur = seusers;
+	char *end = seusers + seusers_len;
+	char *line = NULL;
+	char *user = NULL;
+	char *seuser = NULL;
+	char *level = NULL;
+	char *tmp = NULL;
+	int matched;
+
+	if (seusers_len == 0) {
+		return 0;
+	}
+
+	while ((rc = get_line(&cur, end, &line)) > 0) {
+		tmp = line;
+		while (isspace(*tmp)) {
+			tmp++;
+		}
+
+		if (tmp[0] == '#' || tmp[0] == '\0') {
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		matched = tokenize(tmp, ':', 3, &user, &seuser, &level);
+
+		if (matched < 2 || matched > 3) {
+			log_err("Invalid seuser line: %s", line);
+			rc = -1;
+			goto exit;
+		}
+
+		if (!strcmp(user, "__default__")) {
+			cil_printf("(selinuxuserdefault %s (", seuser);
+		} else {
+			cil_printf("(selinuxuser %s %s (", user, seuser);
+		}
+
+		switch (matched) {
+		case 2:
+			cil_printf("systemlow systemlow");
+			break;
+		case 3:
+			level_range_string_to_cil(level);
+			break;
+		}
+
+		cil_printf("))\n");
+
+		free(user);
+		free(seuser);
+		free(level);
+		free(line);
+		user = seuser = level = NULL;
+	}
+
+	if (rc == -1) {
+		cil_printf("Failed to read seusers\n");
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	free(line);
+	free(user);
+	free(seuser);
+	free(level);
+
+	return rc;
+}
+
+static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+	size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
+
+	if (netcons_len > 0) {
+		log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
+	}
+
+	return 0;
+}
+
+static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	char *userx = sepol_module_package_get_user_extra(mod_pkg);
+	size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
+	char *cur = userx;
+	char *end = userx + userx_len;
+	char *line;
+	int matched;
+	char *user = NULL;
+	char *prefix = NULL;
+	int prefix_len = 0;
+	char *user_str = NULL;
+	char *prefix_str = NULL;
+	char *eol = NULL;
+	char *tmp = NULL;
+
+	if (userx_len == 0) {
+		return 0;
+	}
+
+	while ((rc = get_line(&cur, end, &line)) > 0) {
+		tmp = line;
+		while (isspace(*tmp)) {
+			tmp++;
+		}
+
+		if (tmp[0] == '#' || tmp[0] == '\0') {
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		matched = tokenize(tmp, ' ', 4, &user_str, &user, &prefix_str, &prefix);
+		if (matched != 4) {
+			rc = -1;
+			log_err("Invalid user extra line: %s", line);
+			goto exit;
+		}
+
+		prefix_len = strlen(prefix);
+		eol = prefix + prefix_len - 1;
+		if (*eol != ';' || strcmp(user_str, "user") || strcmp(prefix_str, "prefix")) {
+			rc = -1;
+			log_err("Invalid user extra line: %s", line);
+			goto exit;
+		}
+		*eol = '\0';
+
+		cil_println(0, "(userprefix %s %s)", user, prefix);
+		free(user);
+		free(prefix);
+		free(line);
+		free(user_str);
+		free(prefix_str);
+		user = prefix = line = user_str = prefix_str = NULL;
+	}
+
+	if (rc == -1) {
+		cil_printf("Failed to read user_extra\n");
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	free(line);
+	free(user);
+	free(prefix);
+
+	return rc;
+}
+
+static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	char *fc = sepol_module_package_get_file_contexts(mod_pkg);
+	size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
+	char *cur = fc;
+	char *end = fc + fc_len;
+	char *line = NULL;
+	int matched;
+	char *regex = NULL;
+	char *mode = NULL;
+	char *context = NULL;
+	const char *cilmode;
+	char *tmp = NULL;
+
+	if (fc_len == 0) {
+		return 0;
+	}
+
+	while ((rc = get_line(&cur, end, &line)) > 0) {
+		tmp = line;
+		while (isspace(*tmp)) {
+			tmp++;
+		}
+
+		if (tmp[0] == '#' || tmp[0] == '\0') {
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		matched = tokenize(tmp, ' ', 3, &regex, &mode, &context);
+		if (matched < 2 || matched > 3) {
+			rc = -1;
+			log_err("Invalid file context line: %s", line);
+			goto exit;
+		}
+
+		if (matched == 2) {
+			context = mode;
+			mode = NULL;
+		}
+
+		if (mode == NULL) {
+			cilmode = "any";
+		} else if (!strcmp(mode, "--")) {
+			cilmode = "file";
+		} else if (!strcmp(mode, "-d")) {
+			cilmode = "dir";
+		} else if (!strcmp(mode, "-c")) {
+			cilmode = "char";
+		} else if (!strcmp(mode, "-b")) {
+			cilmode = "block";
+		} else if (!strcmp(mode, "-s")) {
+			cilmode = "socket";
+		} else if (!strcmp(mode, "-p")) {
+			cilmode = "pipe";
+		} else if (!strcmp(mode, "-l")) {
+			cilmode = "symlink";
+		} else {
+			rc = -1;
+			log_err("Invalid mode in file context line: %s", line);
+			goto exit;
+		}
+
+		cil_printf("(filecon \"%s\" %s ", regex, cilmode);
+
+		if (!strcmp(context, "<<none>>")) {
+			cil_printf("()");
+		} else {
+			context_string_to_cil(context);
+		}
+
+		cil_printf(")\n");
+
+		free(regex);
+		free(mode);
+		free(context);
+		free(line);
+		regex = mode = context = line = NULL;
+	}
+
+	if (rc == -1) {
+		cil_printf("Failed to read file_contexts_to_cil\n");
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	free(line);
+	free(regex);
+	free(mode);
+	free(context);
+
+	return rc;
+}
+
+
+static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
+	NULL,	// commons, only stored in the global symtab, handled elsewhere
+	class_to_cil,
+	role_to_cil,
+	type_to_cil,
+	user_to_cil,
+	boolean_to_cil,
+	sens_to_cil,
+	cat_to_cil
+};
+
+static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
+{
+	struct type_datum *alias_datum;
+	char *alias_name;
+	struct list_node *curr;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+	struct list *alias_list = typealias_lists[decl->decl_id];
+	int rc = -1;
+
+	if (alias_list == NULL) {
+		return 0;
+	}
+
+	for (curr = alias_list->head; curr != NULL; curr = curr->next) {
+		alias_name = curr->data;
+		alias_datum = hashtab_search(pdb->p_types.table, alias_name);
+		if (alias_datum == NULL) {
+			rc = -1;
+			goto exit;
+		}
+
+		cil_println(indent, "(typealias %s)", alias_name);
+		cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct ebitmap map;
+	struct ebitmap_node *node;
+	unsigned int i;
+	char * key;
+	struct scope_datum *scope;
+	int sym;
+	void *datum;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+
+	for (sym = 0; sym < SYM_NUM; sym++) {
+		if (func_to_cil[sym] == NULL) {
+			continue;
+		}
+
+		map = decl->declared.scope[sym];
+		ebitmap_for_each_bit(&map, node, i) {
+			if (!ebitmap_get_bit(&map, i)) {
+				continue;
+			}
+			key = pdb->sym_val_to_name[sym][i];
+			datum = hashtab_search(pdb->symtab[sym].table, key);
+			if (datum == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			scope = hashtab_search(pdb->scope[sym].table, key);
+			if (scope == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_CATS) {
+			rc = cat_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_LEVELS) {
+			rc = sens_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_CLASSES) {
+			rc = class_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct ebitmap map;
+	struct ebitmap_node *node;
+	unsigned int i;
+	unsigned int j;
+	char * key;
+	int sym;
+	void *datum;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+	struct scope_datum *scope_datum;
+
+	for (sym = 0; sym < SYM_NUM; sym++) {
+		if (func_to_cil[sym] == NULL) {
+			continue;
+		}
+
+		map = decl->required.scope[sym];
+		ebitmap_for_each_bit(&map, node, i) {
+			if (!ebitmap_get_bit(&map, i)) {
+				continue;
+			}
+			key = pdb->sym_val_to_name[sym][i];
+
+			scope_datum = hashtab_search(pdb->scope[sym].table, key);
+			for (j = 0; j < scope_datum->decl_ids_len; j++) {
+				if (scope_datum->decl_ids[j] == decl->decl_id) {
+					break;
+				}
+			}
+			if (j >= scope_datum->decl_ids_len) {
+				// Symbols required in the global scope are also in the
+				// required scope ebitmap of all avrule decls (i.e. required
+				// in all optionals). So we need to look at the scopes of each
+				// symbol in this avrule_decl to determine if it actually is
+				// required in this decl, or if it's just required in the
+				// global scope. If we got here, then this symbol is not
+				// actually required in this scope, so skip it.
+				continue;
+			}
+
+			datum = hashtab_search(pdb->symtab[sym].table, key);
+			if (datum == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
+{
+	int rc = -1;
+	struct map_args *args = arg;
+
+	rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct map_args args;
+	args.pdb = pdb;
+	args.block = block;
+	args.decl_stack = decl_stack;
+	args.indent = indent;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+
+	for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
+		rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
+{
+	// returns 1 if sup is a superset of sub, returns 0 otherwise
+
+	int rc = 0;
+
+	uint32_t i;
+	struct ebitmap sup_map;
+	struct ebitmap sub_map;
+	struct ebitmap res;
+
+	ebitmap_init(&res);
+
+	for (i = 0; i < SYM_NUM; i++) {
+		sup_map = sup->scope[i];
+		sub_map = sub->scope[i];
+
+		ebitmap_and(&res, &sup_map, &sub_map);
+		if (!ebitmap_cmp(&res, &sub_map)) {
+			goto exit;
+		}
+		ebitmap_destroy(&res);
+	}
+
+	if (sup->class_perms_len < sub->class_perms_len) {
+		goto exit;
+	}
+
+	for (i = 0; i < sub->class_perms_len; i++) {
+		sup_map = sup->class_perms_map[i];
+		sub_map = sub->class_perms_map[i];
+
+		ebitmap_and(&res, &sup_map, &sub_map);
+		if (!ebitmap_cmp(&res, &sub_map)) {
+			goto exit;
+		}
+		ebitmap_destroy(&res);
+	}
+
+	rc = 1;
+
+exit:
+
+	ebitmap_destroy(&res);
+	return rc;
+}
+
+static int block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack, int indent)
+{
+	int rc = -1;
+	struct avrule_decl *decl;
+	struct list *attr_list;
+
+	decl = block->branch_list;
+
+	rc = list_init(&attr_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = typealiases_to_cil(indent, pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = declared_scopes_to_cil(indent, pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = required_scopes_to_cil(indent, pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = additive_scopes_to_cil(indent, pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = cond_list_to_cil(indent, pdb, decl->cond_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = cil_print_attr_list(indent, pdb, attr_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+exit:
+	attr_list_destroy(&attr_list);
+	return rc;
+}
+
+static int module_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack, int *indent)
+{
+	int rc = 0;
+	struct avrule_decl *decl;
+	struct avrule_decl *decl_tmp;
+
+	decl = block->branch_list;
+	if (decl == NULL) {
+		goto exit;
+	}
+
+	if (decl->next != NULL) {
+		log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
+	}
+
+	if (block->flags & AVRULE_OPTIONAL) {
+		while (stack->pos > 0) {
+			decl_tmp = stack_peek(stack);
+			if (is_scope_superset(&decl->required, &decl_tmp->required)) {
+				break;
+			}
+
+			stack_pop(stack);
+			(*indent)--;
+			cil_println(*indent, ")");
+		}
+
+		cil_println(*indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
+		(*indent)++;
+	}
+
+	stack_push(stack, decl);
+
+	rc = block_to_cil(pdb, block, stack, *indent);
+	if (rc != 0) {
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+static int global_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack)
+{
+	int rc = 0;
+	struct avrule_decl *decl;
+
+	decl = block->branch_list;
+	if (decl == NULL) {
+		goto exit;
+	}
+
+	if (decl->next != NULL) {
+		log_err("Warning: 'else' not allowed in global block. Dropping from output.");
+	}
+
+	stack_push(stack, decl);
+
+	// type aliases and commons are only stored in the global symtab.
+	// However, to get scoping correct, we assume they are in the
+	// global block
+	rc = hashtab_map(pdb->p_commons.table, common_to_cil, NULL);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = block_to_cil(pdb, block, stack, 0);
+	if (rc != 0) {
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+
+static int blocks_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	struct avrule_block *block;
+	int indent = 0;
+	struct stack *stack;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	block = pdb->global;
+	rc = global_block_to_cil(pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (block = block->next; block != NULL; block = block->next) {
+		rc = module_block_to_cil(pdb, block, stack, &indent);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	while (indent > 0) {
+		indent--;
+		cil_println(indent, ")");
+	}
+
+exit:
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+static int linked_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack)
+{
+	int rc = 0;
+	struct avrule_decl *decl;
+
+	decl = block->branch_list;
+	if (decl == NULL) {
+		goto exit;
+	}
+
+	if (!decl->enabled) {
+		if (decl->next != NULL) {
+			decl = decl->next;
+		} else {
+			goto exit;
+		}
+	}
+
+	stack_push(stack, decl);
+
+	rc = block_to_cil(pdb, block, stack, 0);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	stack_pop(stack);
+
+exit:
+	return rc;
+}
+
+static int linked_blocks_to_cil(struct policydb *pdb)
+{
+	// Convert base module that has been linked to CIL
+	// Since it is linked, all optional blocks have been resolved
+	int rc = -1;
+	struct avrule_block *block;
+	struct stack *stack;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	block = pdb->global;
+	rc = global_block_to_cil(pdb, block, stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (block = block->next; block != NULL; block = block->next) {
+		rc = linked_block_to_cil(pdb, block, stack);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+static int handle_unknown_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	const char *hu;
+
+	switch (pdb->handle_unknown) {
+	case SEPOL_DENY_UNKNOWN:
+		hu = "deny";
+		break;
+	case SEPOL_REJECT_UNKNOWN:
+		hu = "reject";
+		break;
+	case SEPOL_ALLOW_UNKNOWN:
+		hu = "allow";
+		break;
+	default:
+		log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_println(0, "(handleunknown %s)", hu);
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int generate_mls(struct policydb *pdb)
+{
+	const char *mls_str = pdb->mls ? "true" : "false";
+	cil_println(0, "(mls %s)", mls_str);
+
+	return 0;
+}
+
+static int generate_default_level(void)
+{
+	cil_println(0, "(sensitivity s0)");
+	cil_println(0, "(sensitivityorder (s0))");
+	cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
+
+	return 0;
+}
+
+static int generate_default_object(void)
+{
+	cil_println(0, "(role " DEFAULT_OBJECT ")");
+
+	return 0;
+}
+
+static int generate_builtin_roles(void)
+{
+	// due to inconsistentencies between policies and CIL not allowing
+	// duplicate roles, some roles are always created, regardless of if they
+	// are declared in modules or not
+	cil_println(0, "(role auditadm_r)");
+	cil_println(0, "(role secadm_r)");
+
+	return 0;
+}
+
+static int generate_gen_require_attribute(void)
+{
+	cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
+	cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
+
+	return 0;
+}
+
+static int fix_module_name(struct policydb *pdb)
+{
+	char *letter;
+	int rc = -1;
+
+	// The base module doesn't have its name set, but we use that for some
+	// autogenerated names, like optionals and attributes, to prevent naming
+	// collisions. However, they sometimes need to be fixed up.
+
+	// the base module isn't given a name, so just call it "base"
+	if (pdb->policy_type == POLICY_BASE) {
+		pdb->name = strdup("base");
+		if (pdb->name == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+	}
+
+	// CIL is more restrictive in module names than checkmodule. Convert bad
+	// characters to underscores
+	for (letter = pdb->name; *letter != '\0'; letter++) {
+		if (isalnum(*letter)) {
+			continue;
+		}
+
+		*letter = '_';
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+int sepol_module_policydb_to_cil(FILE *fp, struct policydb *pdb, int linked)
+{
+	int rc = -1;
+
+	out_file = fp;
+
+	if (pdb == NULL) {
+		rc = 0;
+		goto exit;
+	}
+
+	if (pdb->policy_type != SEPOL_POLICY_BASE &&
+		pdb->policy_type != SEPOL_POLICY_MOD) {
+		log_err("Policy pakcage is not a base or module");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = fix_module_name(pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (pdb->policy_type == SEPOL_POLICY_BASE && !pdb->mls) {
+		// If this is a base non-mls policy, we need to define a default level
+		// range that can be used for contexts by other non-mls modules, since
+		// CIL requires that all contexts have a range, even if they are
+		// ignored as in non-mls policies
+		rc = generate_default_level();
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	if (pdb->policy_type == SEPOL_POLICY_BASE) {
+		// object_r is implicit in checkmodule, but not with CIL, create it
+		// as part of base
+		rc = generate_default_object();
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = generate_builtin_roles();
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// default attribute to be used to mimic gen_require in CIL
+		rc = generate_gen_require_attribute();
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// handle_unknown is used from only the base module
+		rc = handle_unknown_to_cil(pdb);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// mls is used from only the base module
+		rc = generate_mls(pdb);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	rc = role_list_create(pdb->p_roles.table);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = typealias_list_create(pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = polcaps_to_cil(pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = ocontexts_to_cil(pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = genfscon_to_cil(pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	// now print everything that is scoped
+	if (linked) {
+		rc = linked_blocks_to_cil(pdb);
+	} else {
+		rc = blocks_to_cil(pdb);
+	}
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	role_list_destroy();
+	typealias_list_destroy();
+
+	return rc;
+}
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	struct sepol_policydb *pdb;
+
+	out_file = fp;
+
+	pdb = sepol_module_package_get_policy(mod_pkg);
+	if (pdb == NULL) {
+		log_err("Failed to get policydb");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = sepol_module_policydb_to_cil(fp, &pdb->p, 0);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = seusers_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = netfilter_contexts_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = user_extra_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = file_contexts_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
+{
+	int rc = -1;
+	char *d = NULL;
+	size_t d_len = 0;
+	size_t read_len = 0;
+	size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
+
+	d = malloc(max_len);
+	if (d == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
+		d_len += read_len;
+		if (d_len == max_len) {
+			max_len *= 2;
+			d = realloc(d, max_len);
+			if (d == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+		}
+	}
+
+	if (ferror(fp) != 0) {
+		log_err("Failed to read pp file");
+		rc = -1;
+		goto exit;
+	}
+
+	*data = d;
+	*data_len = d_len;
+
+	return 0;
+
+exit:
+	free(d);
+	return rc;
+}
+
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
+{
+	int rc = -1;
+	FILE *f = NULL;
+	struct sepol_policy_file *pf = NULL;
+	struct sepol_module_package *pkg = NULL;
+	char *data = NULL;
+	size_t data_len;
+	int fd;
+	struct stat sb;
+
+	rc = sepol_policy_file_create(&pf);
+	if (rc != 0) {
+		log_err("Failed to create policy file");
+		goto exit;
+	}
+
+	fd = fileno(fp);
+	if (fstat(fd, &sb) == -1) {
+		rc = -1;
+		goto exit;
+	}
+
+	if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
+		// libsepol fails when trying to read a policy package from a pipe or a
+		// socket due its use of lseek. In this case, read the data into a
+		// buffer and provide that to libsepol
+		rc = fp_to_buffer(fp, &data, &data_len);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		sepol_policy_file_set_mem(pf, data, data_len);
+	} else {
+		sepol_policy_file_set_fp(pf, fp);
+	}
+
+	rc = sepol_module_package_create(&pkg);
+	if (rc != 0) {
+		log_err("Failed to create module package");
+		goto exit;
+	}
+
+	rc = sepol_module_package_read(pkg, pf, 0);
+	if (rc != 0) {
+		log_err("Failed to read policy package");
+		goto exit;
+	}
+
+	*mod_pkg = pkg;
+
+exit:
+	free(data);
+
+	sepol_policy_file_free(pf);
+	if (f != NULL) {
+		fclose(f);
+	}
+
+	if (rc != 0) {
+		sepol_module_package_free(pkg);
+	}
+
+	return rc;
+}
diff --git a/libsepol/src/node_internal.h b/libsepol/src/node_internal.h
new file mode 100644
index 0000000..802cda9
--- /dev/null
+++ b/libsepol/src/node_internal.h
@@ -0,0 +1,26 @@
+#ifndef _SEPOL_NODE_INTERNAL_H_
+#define _SEPOL_NODE_INTERNAL_H_
+
+#include <sepol/node_record.h>
+#include <sepol/nodes.h>
+#include "dso.h"
+
+hidden_proto(sepol_node_create)
+    hidden_proto(sepol_node_key_free)
+    hidden_proto(sepol_node_free)
+    hidden_proto(sepol_node_get_con)
+    hidden_proto(sepol_node_get_addr)
+    hidden_proto(sepol_node_get_addr_bytes)
+    hidden_proto(sepol_node_get_mask)
+    hidden_proto(sepol_node_get_mask_bytes)
+    hidden_proto(sepol_node_get_proto)
+    hidden_proto(sepol_node_get_proto_str)
+    hidden_proto(sepol_node_key_create)
+    hidden_proto(sepol_node_key_unpack)
+    hidden_proto(sepol_node_set_con)
+    hidden_proto(sepol_node_set_addr)
+    hidden_proto(sepol_node_set_addr_bytes)
+    hidden_proto(sepol_node_set_mask)
+    hidden_proto(sepol_node_set_mask_bytes)
+    hidden_proto(sepol_node_set_proto)
+#endif
diff --git a/libsepol/src/node_record.c b/libsepol/src/node_record.c
new file mode 100644
index 0000000..21043b6
--- /dev/null
+++ b/libsepol/src/node_record.c
@@ -0,0 +1,675 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "node_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_node {
+
+	/* Network address and mask */
+	char *addr;
+	size_t addr_sz;
+
+	char *mask;
+	size_t mask_sz;
+
+	/* Protocol */
+	int proto;
+
+	/* Context */
+	sepol_context_t *con;
+};
+
+struct sepol_node_key {
+
+	/* Network address and mask */
+	char *addr;
+	size_t addr_sz;
+
+	char *mask;
+	size_t mask_sz;
+
+	/* Protocol */
+	int proto;
+};
+
+/* Converts a string represtation (addr_str)
+ * to a numeric representation (addr_bytes) */
+
+static int node_parse_addr(sepol_handle_t * handle,
+			   const char *addr_str, int proto, char *addr_bytes)
+{
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		{
+			struct in_addr in_addr;
+
+			if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) {
+				ERR(handle, "could not parse IPv4 address "
+				    "%s: %s", addr_str, strerror(errno));
+				return STATUS_ERR;
+			}
+
+			memcpy(addr_bytes, &in_addr.s_addr, 4);
+			break;
+		}
+	case SEPOL_PROTO_IP6:
+		{
+			struct in6_addr in_addr;
+
+			if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) {
+				ERR(handle, "could not parse IPv6 address "
+				    "%s: %s", addr_str, strerror(errno));
+				return STATUS_ERR;
+			}
+
+#ifdef __APPLE__
+			memcpy(addr_bytes, in_addr.s6_addr, 16);
+#else
+			memcpy(addr_bytes, in_addr.s6_addr32, 16);
+#endif
+			break;
+		}
+	default:
+		ERR(handle, "unsupported protocol %u, could not "
+		    "parse address", proto);
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large buffer (addr, addr_sz)
+ * according the the protocol */
+
+static int node_alloc_addr(sepol_handle_t * handle,
+			   int proto, char **addr, size_t * addr_sz)
+{
+
+	char *tmp_addr = NULL;
+	size_t tmp_addr_sz;
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		tmp_addr_sz = 4;
+		tmp_addr = malloc(4);
+		if (!tmp_addr)
+			goto omem;
+		break;
+
+	case SEPOL_PROTO_IP6:
+		tmp_addr_sz = 16;
+		tmp_addr = malloc(16);
+		if (!tmp_addr)
+			goto omem;
+		break;
+
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+
+	*addr = tmp_addr;
+	*addr_sz = tmp_addr_sz;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	free(tmp_addr);
+	ERR(handle, "could not allocate address of protocol %s",
+	    sepol_node_get_proto_str(proto));
+	return STATUS_ERR;
+}
+
+/* Converts a numeric representation (addr_bytes)
+ * to a string representation (addr_str), according to 
+ * the protocol */
+
+static int node_expand_addr(sepol_handle_t * handle,
+			    char *addr_bytes, int proto, char *addr_str)
+{
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		{
+			struct in_addr addr;
+			memset(&addr, 0, sizeof(struct in_addr));
+			memcpy(&addr.s_addr, addr_bytes, 4);
+
+			if (inet_ntop(AF_INET, &addr, addr_str,
+				      INET_ADDRSTRLEN) == NULL) {
+
+				ERR(handle,
+				    "could not expand IPv4 address to string: %s",
+				    strerror(errno));
+				return STATUS_ERR;
+			}
+			break;
+		}
+
+	case SEPOL_PROTO_IP6:
+		{
+			struct in6_addr addr;
+			memset(&addr, 0, sizeof(struct in6_addr));
+#ifdef __APPLE__
+			memcpy(&addr.s6_addr[0], addr_bytes, 16);
+#else
+			memcpy(&addr.s6_addr32[0], addr_bytes, 16);
+#endif
+			if (inet_ntop(AF_INET6, &addr, addr_str,
+				      INET6_ADDRSTRLEN) == NULL) {
+
+				ERR(handle,
+				    "could not expand IPv6 address to string: %s",
+				    strerror(errno));
+				return STATUS_ERR;
+			}
+			break;
+		}
+
+	default:
+		ERR(handle, "unsupported protocol %u, could not"
+		    " expand address to string", proto);
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large address string (addr)
+ * according to the protocol */
+
+static int node_alloc_addr_string(sepol_handle_t * handle,
+				  int proto, char **addr)
+{
+
+	char *tmp_addr = NULL;
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		tmp_addr = malloc(INET_ADDRSTRLEN);
+		if (!tmp_addr)
+			goto omem;
+		break;
+
+	case SEPOL_PROTO_IP6:
+		tmp_addr = malloc(INET6_ADDRSTRLEN);
+		if (!tmp_addr)
+			goto omem;
+		break;
+
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+
+	*addr = tmp_addr;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	free(tmp_addr);
+	ERR(handle, "could not allocate string buffer for "
+	    "address of protocol %s", sepol_node_get_proto_str(proto));
+	return STATUS_ERR;
+}
+
+/* Key */
+int sepol_node_key_create(sepol_handle_t * handle,
+			  const char *addr,
+			  const char *mask,
+			  int proto, sepol_node_key_t ** key_ptr)
+{
+
+	sepol_node_key_t *tmp_key =
+	    (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+	if (!tmp_key)
+		goto omem;
+
+	if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) <
+	    0)
+		goto err;
+	if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0)
+		goto err;
+
+	if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) <
+	    0)
+		goto err;
+	if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0)
+		goto err;
+
+	tmp_key->proto = proto;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	sepol_node_key_free(tmp_key);
+	ERR(handle, "could not create node key for (%s, %s, %s)",
+	    addr, mask, sepol_node_get_proto_str(proto));
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_node_key_create)
+
+void sepol_node_key_unpack(const sepol_node_key_t * key,
+			   const char **addr, const char **mask, int *proto)
+{
+
+	*addr = key->addr;
+	*mask = key->mask;
+	*proto = key->proto;
+}
+
+hidden_def(sepol_node_key_unpack)
+
+int sepol_node_key_extract(sepol_handle_t * handle,
+			   const sepol_node_t * node,
+			   sepol_node_key_t ** key_ptr)
+{
+
+	sepol_node_key_t *tmp_key =
+	    (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+	if (!tmp_key)
+		goto omem;
+
+	tmp_key->addr = malloc(node->addr_sz);
+	tmp_key->mask = malloc(node->mask_sz);
+
+	if (!tmp_key->addr || !tmp_key->mask)
+		goto omem;
+
+	memcpy(tmp_key->addr, node->addr, node->addr_sz);
+	memcpy(tmp_key->mask, node->mask, node->mask_sz);
+	tmp_key->addr_sz = node->addr_sz;
+	tmp_key->mask_sz = node->mask_sz;
+	tmp_key->proto = node->proto;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+
+      omem:
+	sepol_node_key_free(tmp_key);
+	ERR(handle, "out of memory, could not extract node key");
+	return STATUS_ERR;
+}
+
+void sepol_node_key_free(sepol_node_key_t * key)
+{
+
+	if (!key)
+		return;
+
+	free(key->addr);
+	free(key->mask);
+	free(key);
+}
+
+hidden_def(sepol_node_key_free)
+
+int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key)
+{
+
+	int rc1, rc2;
+
+	if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz))
+		return -1;
+
+	else if ((node->addr_sz > key->addr_sz) ||
+		 (node->mask_sz > key->mask_sz))
+		return 1;
+
+	rc1 = memcmp(node->addr, key->addr, node->addr_sz);
+	rc2 = memcmp(node->mask, key->mask, node->mask_sz);
+
+	return (rc2 != 0) ? rc2 : rc1;
+}
+
+int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2)
+{
+
+	int rc1, rc2;
+
+	if ((node->addr_sz < node2->addr_sz) ||
+	    (node->mask_sz < node2->mask_sz))
+		return -1;
+
+	else if ((node->addr_sz > node2->addr_sz) ||
+		 (node->mask_sz > node2->mask_sz))
+		return 1;
+
+	rc1 = memcmp(node->addr, node2->addr, node->addr_sz);
+	rc2 = memcmp(node->mask, node2->mask, node->mask_sz);
+
+	return (rc2 != 0) ? rc2 : rc1;
+}
+
+/* Addr */
+int sepol_node_get_addr(sepol_handle_t * handle,
+			const sepol_node_t * node, char **addr)
+{
+
+	char *tmp_addr = NULL;
+
+	if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0)
+		goto err;
+
+	if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0)
+		goto err;
+
+	*addr = tmp_addr;
+	return STATUS_SUCCESS;
+
+      err:
+	free(tmp_addr);
+	ERR(handle, "could not get node address");
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_addr)
+
+int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+			      const sepol_node_t * node,
+			      char **buffer, size_t * bsize)
+{
+
+	char *tmp_buf = malloc(node->addr_sz);
+	if (!tmp_buf) {
+		ERR(handle, "out of memory, could not get address bytes");
+		return STATUS_ERR;
+	}
+
+	memcpy(tmp_buf, node->addr, node->addr_sz);
+	*buffer = tmp_buf;
+	*bsize = node->addr_sz;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_addr_bytes)
+
+int sepol_node_set_addr(sepol_handle_t * handle,
+			sepol_node_t * node, int proto, const char *addr)
+{
+
+	char *tmp_addr = NULL;
+	size_t tmp_addr_sz;
+
+	if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0)
+		goto err;
+
+	if (node_parse_addr(handle, addr, proto, tmp_addr) < 0)
+		goto err;
+
+	free(node->addr);
+	node->addr = tmp_addr;
+	node->addr_sz = tmp_addr_sz;
+	return STATUS_SUCCESS;
+
+      err:
+	free(tmp_addr);
+	ERR(handle, "could not set node address to %s", addr);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_addr)
+
+int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+			      sepol_node_t * node,
+			      const char *addr, size_t addr_sz)
+{
+
+	char *tmp_addr = malloc(addr_sz);
+	if (!tmp_addr) {
+		ERR(handle, "out of memory, could not " "set node address");
+		return STATUS_ERR;
+	}
+
+	memcpy(tmp_addr, addr, addr_sz);
+	free(node->addr);
+	node->addr = tmp_addr;
+	node->addr_sz = addr_sz;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_addr_bytes)
+
+/* Mask */
+int sepol_node_get_mask(sepol_handle_t * handle,
+			const sepol_node_t * node, char **mask)
+{
+
+	char *tmp_mask = NULL;
+
+	if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0)
+		goto err;
+
+	if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0)
+		goto err;
+
+	*mask = tmp_mask;
+	return STATUS_SUCCESS;
+
+      err:
+	free(tmp_mask);
+	ERR(handle, "could not get node netmask");
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_mask)
+
+int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+			      const sepol_node_t * node,
+			      char **buffer, size_t * bsize)
+{
+
+	char *tmp_buf = malloc(node->mask_sz);
+	if (!tmp_buf) {
+		ERR(handle, "out of memory, could not get netmask bytes");
+		return STATUS_ERR;
+	}
+
+	memcpy(tmp_buf, node->mask, node->mask_sz);
+	*buffer = tmp_buf;
+	*bsize = node->mask_sz;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_mask_bytes)
+
+int sepol_node_set_mask(sepol_handle_t * handle,
+			sepol_node_t * node, int proto, const char *mask)
+{
+
+	char *tmp_mask = NULL;
+	size_t tmp_mask_sz;
+
+	if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0)
+		goto err;
+
+	if (node_parse_addr(handle, mask, proto, tmp_mask) < 0)
+		goto err;
+
+	free(node->mask);
+	node->mask = tmp_mask;
+	node->mask_sz = tmp_mask_sz;
+	return STATUS_SUCCESS;
+
+      err:
+	free(tmp_mask);
+	ERR(handle, "could not set node netmask to %s", mask);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_mask)
+
+int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+			      sepol_node_t * node,
+			      const char *mask, size_t mask_sz)
+{
+
+	char *tmp_mask = malloc(mask_sz);
+	if (!tmp_mask) {
+		ERR(handle, "out of memory, could not " "set node netmask");
+		return STATUS_ERR;
+	}
+	memcpy(tmp_mask, mask, mask_sz);
+	free(node->mask);
+	node->mask = tmp_mask;
+	node->mask_sz = mask_sz;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_mask_bytes)
+
+/* Protocol */
+int sepol_node_get_proto(const sepol_node_t * node)
+{
+
+	return node->proto;
+}
+
+hidden_def(sepol_node_get_proto)
+
+void sepol_node_set_proto(sepol_node_t * node, int proto)
+{
+
+	node->proto = proto;
+}
+
+hidden_def(sepol_node_set_proto)
+
+const char *sepol_node_get_proto_str(int proto)
+{
+
+	switch (proto) {
+	case SEPOL_PROTO_IP4:
+		return "ipv4";
+	case SEPOL_PROTO_IP6:
+		return "ipv6";
+	default:
+		return "???";
+	}
+}
+
+hidden_def(sepol_node_get_proto_str)
+
+/* Create */
+int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node)
+{
+
+	sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t));
+
+	if (!tmp_node) {
+		ERR(handle, "out of memory, could not create " "node record");
+		return STATUS_ERR;
+	}
+
+	tmp_node->addr = NULL;
+	tmp_node->addr_sz = 0;
+	tmp_node->mask = NULL;
+	tmp_node->mask_sz = 0;
+	tmp_node->proto = SEPOL_PROTO_IP4;
+	tmp_node->con = NULL;
+	*node = tmp_node;
+
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_create)
+
+/* Deep copy clone */
+int sepol_node_clone(sepol_handle_t * handle,
+		     const sepol_node_t * node, sepol_node_t ** node_ptr)
+{
+
+	sepol_node_t *new_node = NULL;
+	if (sepol_node_create(handle, &new_node) < 0)
+		goto err;
+
+	/* Copy address, mask, protocol */
+	new_node->addr = malloc(node->addr_sz);
+	new_node->mask = malloc(node->mask_sz);
+	if (!new_node->addr || !new_node->mask)
+		goto omem;
+
+	memcpy(new_node->addr, node->addr, node->addr_sz);
+	memcpy(new_node->mask, node->mask, node->mask_sz);
+	new_node->addr_sz = node->addr_sz;
+	new_node->mask_sz = node->mask_sz;
+	new_node->proto = node->proto;
+
+	/* Copy context */
+	if (node->con &&
+	    (sepol_context_clone(handle, node->con, &new_node->con) < 0))
+		goto err;
+
+	*node_ptr = new_node;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not clone node record");
+	sepol_node_free(new_node);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_node_free(sepol_node_t * node)
+{
+
+	if (!node)
+		return;
+
+	sepol_context_free(node->con);
+	free(node->addr);
+	free(node->mask);
+	free(node);
+}
+
+hidden_def(sepol_node_free)
+
+/* Context */
+sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
+{
+
+	return node->con;
+}
+
+hidden_def(sepol_node_get_con)
+
+int sepol_node_set_con(sepol_handle_t * handle,
+		       sepol_node_t * node, sepol_context_t * con)
+{
+
+	sepol_context_t *newcon;
+
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set node context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(node->con);
+	node->con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_con)
diff --git a/libsepol/src/nodes.c b/libsepol/src/nodes.c
new file mode 100644
index 0000000..50cf21d
--- /dev/null
+++ b/libsepol/src/nodes.c
@@ -0,0 +1,399 @@
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "node_internal.h"
+
+/* Create a low level node structure from
+ * a high level representation */
+static int node_from_record(sepol_handle_t * handle,
+			    const policydb_t * policydb,
+			    ocontext_t ** node, const sepol_node_t * data)
+{
+
+	ocontext_t *tmp_node = NULL;
+	context_struct_t *tmp_con = NULL;
+	char *addr_buf = NULL, *mask_buf = NULL;
+
+	tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+	if (!tmp_node)
+		goto omem;
+
+	size_t addr_bsize, mask_bsize;
+
+	/* Address and netmask */
+	if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
+		goto err;
+	if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
+		goto err;
+
+	int proto = sepol_node_get_proto(data);
+
+	switch (proto) {
+	case SEPOL_PROTO_IP4:
+		memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
+		memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
+		break;
+	case SEPOL_PROTO_IP6:
+		memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
+		memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
+		break;
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+	free(addr_buf);
+	free(mask_buf);
+	addr_buf = NULL;
+	mask_buf = NULL;
+
+	/* Context */
+	if (context_from_record(handle, policydb, &tmp_con,
+				sepol_node_get_con(data)) < 0)
+		goto err;
+	context_cpy(&tmp_node->context[0], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	*node = tmp_node;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	if (tmp_node != NULL) {
+		context_destroy(&tmp_node->context[0]);
+		free(tmp_node);
+	}
+	context_destroy(tmp_con);
+	free(tmp_con);
+	free(addr_buf);
+	free(mask_buf);
+	ERR(handle, "could not create node structure");
+	return STATUS_ERR;
+}
+
+static int node_to_record(sepol_handle_t * handle,
+			  const policydb_t * policydb,
+			  ocontext_t * node, int proto, sepol_node_t ** record)
+{
+
+	context_struct_t *con = &node->context[0];
+
+	sepol_context_t *tmp_con = NULL;
+	sepol_node_t *tmp_record = NULL;
+
+	if (sepol_node_create(handle, &tmp_record) < 0)
+		goto err;
+
+	sepol_node_set_proto(tmp_record, proto);
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		if (sepol_node_set_addr_bytes(handle, tmp_record,
+					      (const char *)&node->u.node.addr,
+					      4) < 0)
+			goto err;
+
+		if (sepol_node_set_mask_bytes(handle, tmp_record,
+					      (const char *)&node->u.node.mask,
+					      4) < 0)
+			goto err;
+		break;
+
+	case SEPOL_PROTO_IP6:
+		if (sepol_node_set_addr_bytes(handle, tmp_record,
+					      (const char *)&node->u.node6.addr,
+					      16) < 0)
+			goto err;
+
+		if (sepol_node_set_mask_bytes(handle, tmp_record,
+					      (const char *)&node->u.node6.mask,
+					      16) < 0)
+			goto err;
+		break;
+
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+
+	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+		goto err;
+
+	if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
+		goto err;
+
+	sepol_context_free(tmp_con);
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not convert node to record");
+	sepol_context_free(tmp_con);
+	sepol_node_free(tmp_record);
+	return STATUS_ERR;
+}
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
+			    const sepol_policydb_t * p, unsigned int *response)
+{
+
+	unsigned int count = 0;
+	ocontext_t *c, *head;
+	const policydb_t *policydb = &p->p;
+
+	head = policydb->ocontexts[OCON_NODE];
+	for (c = head; c != NULL; c = c->next)
+		count++;
+
+	head = policydb->ocontexts[OCON_NODE6];
+	for (c = head; c != NULL; c = c->next)
+		count++;
+
+	*response = count;
+
+	return STATUS_SUCCESS;
+}
+
+/* Check if a node exists */
+int sepol_node_exists(sepol_handle_t * handle,
+		      const sepol_policydb_t * p,
+		      const sepol_node_key_t * key, int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	int proto;
+	const char *addr, *mask;
+	sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		{
+			head = policydb->ocontexts[OCON_NODE];
+			for (c = head; c; c = c->next) {
+				unsigned int *addr2 = &c->u.node.addr;
+				unsigned int *mask2 = &c->u.node.mask;
+
+				if (!memcmp(addr, addr2, 4) &&
+				    !memcmp(mask, mask2, 4)) {
+
+					*response = 1;
+					return STATUS_SUCCESS;
+				}
+			}
+			break;
+		}
+	case SEPOL_PROTO_IP6:
+		{
+			head = policydb->ocontexts[OCON_NODE6];
+			for (c = head; c; c = c->next) {
+				unsigned int *addr2 = c->u.node6.addr;
+				unsigned int *mask2 = c->u.node6.mask;
+
+				if (!memcmp(addr, addr2, 16) &&
+				    !memcmp(mask, mask2, 16)) {
+					*response = 1;
+					return STATUS_SUCCESS;
+				}
+			}
+			break;
+		}
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+
+	*response = 0;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not check if node %s/%s (%s) exists",
+	    addr, mask, sepol_node_get_proto_str(proto));
+	return STATUS_ERR;
+}
+
+/* Query a node */
+int sepol_node_query(sepol_handle_t * handle,
+		     const sepol_policydb_t * p,
+		     const sepol_node_key_t * key, sepol_node_t ** response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	int proto;
+	const char *addr, *mask;
+	sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		{
+			head = policydb->ocontexts[OCON_NODE];
+			for (c = head; c; c = c->next) {
+				unsigned int *addr2 = &c->u.node.addr;
+				unsigned int *mask2 = &c->u.node.mask;
+
+				if (!memcmp(addr, addr2, 4) &&
+				    !memcmp(mask, mask2, 4)) {
+
+					if (node_to_record(handle, policydb,
+							   c, SEPOL_PROTO_IP4,
+							   response) < 0)
+						goto err;
+					return STATUS_SUCCESS;
+				}
+			}
+			break;
+		}
+	case SEPOL_PROTO_IP6:
+		{
+			head = policydb->ocontexts[OCON_NODE6];
+			for (c = head; c; c = c->next) {
+				unsigned int *addr2 = c->u.node6.addr;
+				unsigned int *mask2 = c->u.node6.mask;
+
+				if (!memcmp(addr, addr2, 16) &&
+				    !memcmp(mask, mask2, 16)) {
+
+					if (node_to_record(handle, policydb,
+							   c, SEPOL_PROTO_IP6,
+							   response) < 0)
+						goto err;
+				}
+			}
+			break;
+		}
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+	*response = NULL;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not query node %s/%s (%s)",
+	    addr, mask, sepol_node_get_proto_str(proto));
+	return STATUS_ERR;
+
+}
+
+/* Load a node into policy */
+int sepol_node_modify(sepol_handle_t * handle,
+		      sepol_policydb_t * p,
+		      const sepol_node_key_t * key, const sepol_node_t * data)
+{
+
+	policydb_t *policydb = &p->p;
+	ocontext_t *node = NULL;
+
+	int proto;
+	const char *addr, *mask;
+
+	sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+	if (node_from_record(handle, policydb, &node, data) < 0)
+		goto err;
+
+	switch (proto) {
+
+	case SEPOL_PROTO_IP4:
+		{
+			/* Attach to context list */
+			node->next = policydb->ocontexts[OCON_NODE];
+			policydb->ocontexts[OCON_NODE] = node;
+			break;
+		}
+	case SEPOL_PROTO_IP6:
+		{
+			/* Attach to context list */
+			node->next = policydb->ocontexts[OCON_NODE6];
+			policydb->ocontexts[OCON_NODE6] = node;
+			break;
+		}
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		goto err;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not load node %s/%s (%s)",
+	    addr, mask, sepol_node_get_proto_str(proto));
+	if (node != NULL) {
+		context_destroy(&node->context[0]);
+		free(node);
+	}
+	return STATUS_ERR;
+}
+
+int sepol_node_iterate(sepol_handle_t * handle,
+		       const sepol_policydb_t * p,
+		       int (*fn) (const sepol_node_t * node,
+				  void *fn_arg), void *arg)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	sepol_node_t *node = NULL;
+	int status;
+
+	head = policydb->ocontexts[OCON_NODE];
+	for (c = head; c; c = c->next) {
+		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
+		    < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(node, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_node_free(node);
+		node = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	head = policydb->ocontexts[OCON_NODE6];
+	for (c = head; c; c = c->next) {
+		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
+		    < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(node, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_node_free(node);
+		node = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not iterate over nodes");
+	sepol_node_free(node);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/polcaps.c b/libsepol/src/polcaps.c
new file mode 100644
index 0000000..43a71a7
--- /dev/null
+++ b/libsepol/src/polcaps.c
@@ -0,0 +1,35 @@
+/*
+ * Policy capability support functions
+ */
+
+#include <string.h>
+#include <sepol/policydb/polcaps.h>
+
+static const char *polcap_names[] = {
+	"network_peer_controls",	/* POLICYDB_CAPABILITY_NETPEER */
+	"open_perms",			/* POLICYDB_CAPABILITY_OPENPERM */
+	"redhat1",			/* POLICYDB_CAPABILITY_REDHAT1, aka ptrace_child */
+	"always_check_network",		/* POLICYDB_CAPABILITY_ALWAYSNETWORK */
+	NULL
+};
+
+int sepol_polcap_getnum(const char *name)
+{
+	int capnum;
+
+	for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) {
+		if (polcap_names[capnum] == NULL)
+			continue;
+		if (strcasecmp(polcap_names[capnum], name) == 0)
+			return capnum;
+	}
+	return -1;
+}
+
+const char *sepol_polcap_getname(int capnum)
+{
+	if (capnum > POLICYDB_CAPABILITY_MAX)
+		return NULL;
+
+	return polcap_names[capnum];
+}
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
new file mode 100644
index 0000000..6a80f94
--- /dev/null
+++ b/libsepol/src/policydb.c
@@ -0,0 +1,3992 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ * 
+ * Updated: Red Hat, Inc.  James Morris <jmorris@redhat.com>
+ *      Fine-grained netlink support
+ *      IPv6 support
+ *      Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2007 Red Hat, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the policy database.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/flask.h>
+
+#include "private.h"
+#include "debug.h"
+#include "mls.h"
+
+#define POLICYDB_TARGET_SZ   ARRAY_SIZE(policydb_target_strings)
+const char *policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING };
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_XEN_PCIDEVICE + 1,
+	 .target_platform = SEPOL_TARGET_XEN,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_XEN_DEVICETREE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_XEN_DEVICETREE + 1,
+	 .target_platform = SEPOL_TARGET_XEN,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_BASE,
+	 .sym_num = SYM_NUM - 3,
+	 .ocon_num = OCON_FSUSE + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_BOOL,
+	 .sym_num = SYM_NUM - 2,
+	 .ocon_num = OCON_FSUSE + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_IPV6,
+	 .sym_num = SYM_NUM - 2,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_NLCLASS,
+	 .sym_num = SYM_NUM - 2,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_MLS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_AVTAB,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_RANGETRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_POLCAP,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_PERMISSIVE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+        {
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_FILENAME_TRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_ROLETRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_DEFAULT_TYPE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_XPERMS_IOCTL,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_BASE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_MLS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_MLS_USERS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_POLCAP,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_ROLETRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_TUNABLE_SEP,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_BASE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_MLS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_MLS_USERS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_POLCAP,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_ROLETRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_TUNABLE_SEP,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+};
+
+#if 0
+static char *symtab_name[SYM_NUM] = {
+	"common prefixes",
+	"classes",
+	"roles",
+	"types",
+	"users",
+	"bools" mls_symtab_names cond_symtab_names
+};
+#endif
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+	2,
+	32,
+	16,
+	512,
+	128,
+	16,
+	16,
+	16,
+};
+
+struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+						    unsigned int type,
+						unsigned int target_platform)
+{
+	unsigned int i;
+	struct policydb_compat_info *info = NULL;
+
+	for (i = 0; i < sizeof(policydb_compat) / sizeof(*info); i++) {
+		if (policydb_compat[i].version == version &&
+		    policydb_compat[i].type == type &&
+		    policydb_compat[i].target_platform == target_platform) {
+			info = &policydb_compat[i];
+			break;
+		}
+	}
+	return info;
+}
+
+void type_set_init(type_set_t * x)
+{
+	memset(x, 0, sizeof(type_set_t));
+	ebitmap_init(&x->types);
+	ebitmap_init(&x->negset);
+}
+
+void type_set_destroy(type_set_t * x)
+{
+	if (x != NULL) {
+		ebitmap_destroy(&x->types);
+		ebitmap_destroy(&x->negset);
+	}
+}
+
+void role_set_init(role_set_t * x)
+{
+	memset(x, 0, sizeof(role_set_t));
+	ebitmap_init(&x->roles);
+}
+
+void role_set_destroy(role_set_t * x)
+{
+	ebitmap_destroy(&x->roles);
+}
+
+void role_datum_init(role_datum_t * x)
+{
+	memset(x, 0, sizeof(role_datum_t));
+	ebitmap_init(&x->dominates);
+	type_set_init(&x->types);
+	ebitmap_init(&x->cache);
+	ebitmap_init(&x->roles);
+}
+
+void role_datum_destroy(role_datum_t * x)
+{
+	if (x != NULL) {
+		ebitmap_destroy(&x->dominates);
+		type_set_destroy(&x->types);
+		ebitmap_destroy(&x->cache);
+		ebitmap_destroy(&x->roles);
+	}
+}
+
+void type_datum_init(type_datum_t * x)
+{
+	memset(x, 0, sizeof(*x));
+	ebitmap_init(&x->types);
+}
+
+void type_datum_destroy(type_datum_t * x)
+{
+	if (x != NULL) {
+		ebitmap_destroy(&x->types);
+	}
+}
+
+void user_datum_init(user_datum_t * x)
+{
+	memset(x, 0, sizeof(user_datum_t));
+	role_set_init(&x->roles);
+	mls_semantic_range_init(&x->range);
+	mls_semantic_level_init(&x->dfltlevel);
+	ebitmap_init(&x->cache);
+	mls_range_init(&x->exp_range);
+	mls_level_init(&x->exp_dfltlevel);
+}
+
+void user_datum_destroy(user_datum_t * x)
+{
+	if (x != NULL) {
+		role_set_destroy(&x->roles);
+		mls_semantic_range_destroy(&x->range);
+		mls_semantic_level_destroy(&x->dfltlevel);
+		ebitmap_destroy(&x->cache);
+		mls_range_destroy(&x->exp_range);
+		mls_level_destroy(&x->exp_dfltlevel);
+	}
+}
+
+void level_datum_init(level_datum_t * x)
+{
+	memset(x, 0, sizeof(level_datum_t));
+}
+
+void level_datum_destroy(level_datum_t * x __attribute__ ((unused)))
+{
+	/* the mls_level_t referenced by the level_datum is managed
+	 * separately for now, so there is nothing to destroy */
+	return;
+}
+
+void cat_datum_init(cat_datum_t * x)
+{
+	memset(x, 0, sizeof(cat_datum_t));
+}
+
+void cat_datum_destroy(cat_datum_t * x __attribute__ ((unused)))
+{
+	/* it's currently a simple struct - really nothing to destroy */
+	return;
+}
+
+void class_perm_node_init(class_perm_node_t * x)
+{
+	memset(x, 0, sizeof(class_perm_node_t));
+}
+
+void avrule_init(avrule_t * x)
+{
+	memset(x, 0, sizeof(avrule_t));
+	type_set_init(&x->stypes);
+	type_set_init(&x->ttypes);
+}
+
+void avrule_destroy(avrule_t * x)
+{
+	class_perm_node_t *cur, *next;
+
+	if (x == NULL) {
+		return;
+	}
+	type_set_destroy(&x->stypes);
+	type_set_destroy(&x->ttypes);
+
+	free(x->source_filename);
+
+	next = x->perms;
+	while (next) {
+		cur = next;
+		next = cur->next;
+		free(cur);
+	}
+}
+
+void role_trans_rule_init(role_trans_rule_t * x)
+{
+	memset(x, 0, sizeof(*x));
+	role_set_init(&x->roles);
+	type_set_init(&x->types);
+	ebitmap_init(&x->classes);
+}
+
+void role_trans_rule_destroy(role_trans_rule_t * x)
+{
+	if (x != NULL) {
+		role_set_destroy(&x->roles);
+		type_set_destroy(&x->types);
+		ebitmap_destroy(&x->classes);
+	}
+}
+
+void role_trans_rule_list_destroy(role_trans_rule_t * x)
+{
+	while (x != NULL) {
+		role_trans_rule_t *next = x->next;
+		role_trans_rule_destroy(x);
+		free(x);
+		x = next;
+	}
+}
+
+void filename_trans_rule_init(filename_trans_rule_t * x)
+{
+	memset(x, 0, sizeof(*x));
+	type_set_init(&x->stypes);
+	type_set_init(&x->ttypes);
+}
+
+static void filename_trans_rule_destroy(filename_trans_rule_t * x)
+{
+	if (!x)
+		return;
+	type_set_destroy(&x->stypes);
+	type_set_destroy(&x->ttypes);
+	free(x->name);
+}
+
+void filename_trans_rule_list_destroy(filename_trans_rule_t * x)
+{
+	filename_trans_rule_t *next;
+	while (x) {
+		next = x->next;
+		filename_trans_rule_destroy(x);
+		free(x);
+		x = next;
+	}
+}
+
+void role_allow_rule_init(role_allow_rule_t * x)
+{
+	memset(x, 0, sizeof(role_allow_rule_t));
+	role_set_init(&x->roles);
+	role_set_init(&x->new_roles);
+}
+
+void role_allow_rule_destroy(role_allow_rule_t * x)
+{
+	role_set_destroy(&x->roles);
+	role_set_destroy(&x->new_roles);
+}
+
+void role_allow_rule_list_destroy(role_allow_rule_t * x)
+{
+	while (x != NULL) {
+		role_allow_rule_t *next = x->next;
+		role_allow_rule_destroy(x);
+		free(x);
+		x = next;
+	}
+}
+
+void range_trans_rule_init(range_trans_rule_t * x)
+{
+	type_set_init(&x->stypes);
+	type_set_init(&x->ttypes);
+	ebitmap_init(&x->tclasses);
+	mls_semantic_range_init(&x->trange);
+	x->next = NULL;
+}
+
+void range_trans_rule_destroy(range_trans_rule_t * x)
+{
+	type_set_destroy(&x->stypes);
+	type_set_destroy(&x->ttypes);
+	ebitmap_destroy(&x->tclasses);
+	mls_semantic_range_destroy(&x->trange);
+}
+
+void range_trans_rule_list_destroy(range_trans_rule_t * x)
+{
+	while (x != NULL) {
+		range_trans_rule_t *next = x->next;
+		range_trans_rule_destroy(x);
+		free(x);
+		x = next;
+	}
+}
+
+void avrule_list_destroy(avrule_t * x)
+{
+	avrule_t *next, *cur;
+
+	if (!x)
+		return;
+
+	next = x;
+	while (next) {
+		cur = next;
+		next = next->next;
+		avrule_destroy(cur);
+		free(cur);
+	}
+}
+
+/* 
+ * Initialize the role table by implicitly adding role 'object_r'.  If
+ * the policy is a module, set object_r's scope to be SCOPE_REQ,
+ * otherwise set it to SCOPE_DECL.
+ */
+static int roles_init(policydb_t * p)
+{
+	char *key = 0;
+	int rc;
+	role_datum_t *role;
+
+	role = calloc(1, sizeof(role_datum_t));
+	if (!role) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	key = malloc(strlen(OBJECT_R) + 1);
+	if (!key) {
+		rc = -ENOMEM;
+		goto out_free_role;
+	}
+	strcpy(key, OBJECT_R);
+	rc = symtab_insert(p, SYM_ROLES, key, role,
+			   (p->policy_type ==
+			    POLICY_MOD ? SCOPE_REQ : SCOPE_DECL), 1,
+			   &role->s.value);
+	if (rc)
+		goto out_free_key;
+	if (role->s.value != OBJECT_R_VAL) {
+		rc = -EINVAL;
+		goto out_free_role;
+	}
+      out:
+	return rc;
+
+      out_free_key:
+	free(key);
+      out_free_role:
+	free(role);
+	goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+int policydb_init(policydb_t * p)
+{
+	int i, rc;
+
+	memset(p, 0, sizeof(policydb_t));
+
+	ebitmap_init(&p->policycaps);
+
+	ebitmap_init(&p->permissive_map);
+
+	for (i = 0; i < SYM_NUM; i++) {
+		p->sym_val_to_name[i] = NULL;
+		rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+		if (rc)
+			goto out_free_symtab;
+	}
+
+	/* initialize the module stuff */
+	for (i = 0; i < SYM_NUM; i++) {
+		if (symtab_init(&p->scope[i], symtab_sizes[i])) {
+			goto out_free_symtab;
+		}
+	}
+	if ((p->global = avrule_block_create()) == NULL ||
+	    (p->global->branch_list = avrule_decl_create(1)) == NULL) {
+		goto out_free_symtab;
+	}
+	p->decl_val_to_struct = NULL;
+
+	rc = avtab_init(&p->te_avtab);
+	if (rc)
+		goto out_free_symtab;
+
+	rc = roles_init(p);
+	if (rc)
+		goto out_free_symtab;
+
+	rc = cond_policydb_init(p);
+	if (rc)
+		goto out_free_symtab;
+      out:
+	return rc;
+
+      out_free_symtab:
+	for (i = 0; i < SYM_NUM; i++) {
+		hashtab_destroy(p->symtab[i].table);
+		hashtab_destroy(p->scope[i].table);
+	}
+	avrule_block_list_destroy(p->global);
+	goto out;
+}
+
+int policydb_role_cache(hashtab_key_t key
+			__attribute__ ((unused)), hashtab_datum_t datum,
+			void *arg)
+{
+	policydb_t *p;
+	role_datum_t *role;
+
+	role = (role_datum_t *) datum;
+	p = (policydb_t *) arg;
+
+	ebitmap_destroy(&role->cache);
+	if (type_set_expand(&role->types, &role->cache, p, 1)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+int policydb_user_cache(hashtab_key_t key
+			__attribute__ ((unused)), hashtab_datum_t datum,
+			void *arg)
+{
+	policydb_t *p;
+	user_datum_t *user;
+
+	user = (user_datum_t *) datum;
+	p = (policydb_t *) arg;
+
+	ebitmap_destroy(&user->cache);
+	if (role_set_expand(&user->roles, &user->cache, p, NULL, NULL)) {
+		return -1;
+	}
+
+	/* we do not expand user's MLS info in kernel policies because the
+	 * semantic representation is not present and we do not expand user's
+	 * MLS info in module policies because all of the necessary mls
+	 * information is not present */
+	if (p->policy_type != POLICY_KERN && p->policy_type != POLICY_MOD) {
+		mls_range_destroy(&user->exp_range);
+		if (mls_semantic_range_expand(&user->range,
+					      &user->exp_range, p, NULL)) {
+			return -1;
+		}
+
+		mls_level_destroy(&user->exp_dfltlevel);
+		if (mls_semantic_level_expand(&user->dfltlevel,
+					      &user->exp_dfltlevel, p, NULL)) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure.  The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations.  The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	common_datum_t *comdatum;
+
+	comdatum = (common_datum_t *) datum;
+	p = (policydb_t *) datap;
+	if (!comdatum->s.value || comdatum->s.value > p->p_commons.nprim)
+		return -EINVAL;
+	p->p_common_val_to_name[comdatum->s.value - 1] = (char *)key;
+
+	return 0;
+}
+
+static int class_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	class_datum_t *cladatum;
+
+	cladatum = (class_datum_t *) datum;
+	p = (policydb_t *) datap;
+	if (!cladatum->s.value || cladatum->s.value > p->p_classes.nprim)
+		return -EINVAL;
+	p->p_class_val_to_name[cladatum->s.value - 1] = (char *)key;
+	p->class_val_to_struct[cladatum->s.value - 1] = cladatum;
+
+	return 0;
+}
+
+static int role_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	role_datum_t *role;
+
+	role = (role_datum_t *) datum;
+	p = (policydb_t *) datap;
+	if (!role->s.value || role->s.value > p->p_roles.nprim)
+		return -EINVAL;
+	p->p_role_val_to_name[role->s.value - 1] = (char *)key;
+	p->role_val_to_struct[role->s.value - 1] = role;
+
+	return 0;
+}
+
+static int type_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	type_datum_t *typdatum;
+
+	typdatum = (type_datum_t *) datum;
+	p = (policydb_t *) datap;
+
+	if (typdatum->primary) {
+		if (!typdatum->s.value || typdatum->s.value > p->p_types.nprim)
+			return -EINVAL;
+		p->p_type_val_to_name[typdatum->s.value - 1] = (char *)key;
+		p->type_val_to_struct[typdatum->s.value - 1] = typdatum;
+	}
+
+	return 0;
+}
+
+static int user_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	user_datum_t *usrdatum;
+
+	usrdatum = (user_datum_t *) datum;
+	p = (policydb_t *) datap;
+
+	if (!usrdatum->s.value || usrdatum->s.value > p->p_users.nprim)
+		return -EINVAL;
+
+	p->p_user_val_to_name[usrdatum->s.value - 1] = (char *)key;
+	p->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+
+	return 0;
+}
+
+static int sens_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	level_datum_t *levdatum;
+
+	levdatum = (level_datum_t *) datum;
+	p = (policydb_t *) datap;
+
+	if (!levdatum->isalias) {
+		if (!levdatum->level->sens ||
+		    levdatum->level->sens > p->p_levels.nprim)
+			return -EINVAL;
+		p->p_sens_val_to_name[levdatum->level->sens - 1] = (char *)key;
+	}
+
+	return 0;
+}
+
+static int cat_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+	policydb_t *p;
+	cat_datum_t *catdatum;
+
+	catdatum = (cat_datum_t *) datum;
+	p = (policydb_t *) datap;
+
+	if (!catdatum->isalias) {
+		if (!catdatum->s.value || catdatum->s.value > p->p_cats.nprim)
+			return -EINVAL;
+		p->p_cat_val_to_name[catdatum->s.value - 1] = (char *)key;
+	}
+
+	return 0;
+}
+
+static int (*index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+				void *datap) = {
+common_index, class_index, role_index, type_index, user_index,
+	    cond_index_bool, sens_index, cat_index,};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.  
+ */
+int policydb_index_classes(policydb_t * p)
+{
+	free(p->p_common_val_to_name);
+	p->p_common_val_to_name = (char **)
+	    malloc(p->p_commons.nprim * sizeof(char *));
+	if (!p->p_common_val_to_name)
+		return -1;
+
+	if (hashtab_map(p->p_commons.table, common_index, p))
+		return -1;
+
+	free(p->class_val_to_struct);
+	p->class_val_to_struct = (class_datum_t **)
+	    malloc(p->p_classes.nprim * sizeof(class_datum_t *));
+	if (!p->class_val_to_struct)
+		return -1;
+
+	free(p->p_class_val_to_name);
+	p->p_class_val_to_name = (char **)
+	    malloc(p->p_classes.nprim * sizeof(char *));
+	if (!p->p_class_val_to_name)
+		return -1;
+
+	if (hashtab_map(p->p_classes.table, class_index, p))
+		return -1;
+
+	return 0;
+}
+
+int policydb_index_bools(policydb_t * p)
+{
+
+	if (cond_init_bool_indexes(p) == -1)
+		return -1;
+	p->p_bool_val_to_name = (char **)
+	    malloc(p->p_bools.nprim * sizeof(char *));
+	if (!p->p_bool_val_to_name)
+		return -1;
+	if (hashtab_map(p->p_bools.table, cond_index_bool, p))
+		return -1;
+	return 0;
+}
+
+int policydb_index_decls(policydb_t * p)
+{
+	avrule_block_t *curblock;
+	avrule_decl_t *decl;
+	int num_decls = 0;
+
+	free(p->decl_val_to_struct);
+
+	for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+		for (decl = curblock->branch_list; decl != NULL;
+		     decl = decl->next) {
+			num_decls++;
+		}
+	}
+
+	p->decl_val_to_struct =
+	    calloc(num_decls, sizeof(*(p->decl_val_to_struct)));
+	if (!p->decl_val_to_struct) {
+		return -1;
+	}
+
+	for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+		for (decl = curblock->branch_list; decl != NULL;
+		     decl = decl->next) {
+			p->decl_val_to_struct[decl->decl_id - 1] = decl;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.  
+ */
+int policydb_index_others(sepol_handle_t * handle,
+			  policydb_t * p, unsigned verbose)
+{
+	int i;
+
+	if (verbose) {
+		INFO(handle,
+		     "security:  %d users, %d roles, %d types, %d bools",
+		     p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
+		     p->p_bools.nprim);
+
+		if (p->mls)
+			INFO(handle, "security: %d sens, %d cats",
+			     p->p_levels.nprim, p->p_cats.nprim);
+
+		INFO(handle, "security:  %d classes, %d rules, %d cond rules",
+		     p->p_classes.nprim, p->te_avtab.nel, p->te_cond_avtab.nel);
+	}
+#if 0
+	avtab_hash_eval(&p->te_avtab, "rules");
+	for (i = 0; i < SYM_NUM; i++)
+		hashtab_hash_eval(p->symtab[i].table, symtab_name[i]);
+#endif
+
+	free(p->role_val_to_struct);
+	p->role_val_to_struct = (role_datum_t **)
+	    malloc(p->p_roles.nprim * sizeof(role_datum_t *));
+	if (!p->role_val_to_struct)
+		return -1;
+
+	free(p->user_val_to_struct);
+	p->user_val_to_struct = (user_datum_t **)
+	    malloc(p->p_users.nprim * sizeof(user_datum_t *));
+	if (!p->user_val_to_struct)
+		return -1;
+
+	free(p->type_val_to_struct);
+	p->type_val_to_struct = (type_datum_t **)
+	    calloc(p->p_types.nprim, sizeof(type_datum_t *));
+	if (!p->type_val_to_struct)
+		return -1;
+
+	cond_init_bool_indexes(p);
+
+	for (i = SYM_ROLES; i < SYM_NUM; i++) {
+		free(p->sym_val_to_name[i]);
+		p->sym_val_to_name[i] = NULL;
+		if (p->symtab[i].nprim) {
+			p->sym_val_to_name[i] = (char **)
+			    calloc(p->symtab[i].nprim, sizeof(char *));
+			if (!p->sym_val_to_name[i])
+				return -1;
+			if (hashtab_map(p->symtab[i].table, index_f[i], p))
+				return -1;
+		}
+	}
+
+	/* This pre-expands the roles and users for context validity checking */
+	if (hashtab_map(p->p_roles.table, policydb_role_cache, p))
+		return -1;
+
+	if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+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 int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			  __attribute__ ((unused)))
+{
+	common_datum_t *comdatum;
+
+	if (key)
+		free(key);
+	comdatum = (common_datum_t *) datum;
+	(void)hashtab_map(comdatum->permissions.table, perm_destroy, 0);
+	hashtab_destroy(comdatum->permissions.table);
+	free(datum);
+	return 0;
+}
+
+static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			 __attribute__ ((unused)))
+{
+	class_datum_t *cladatum;
+	constraint_node_t *constraint, *ctemp;
+	constraint_expr_t *e, *etmp;
+
+	if (key)
+		free(key);
+	cladatum = (class_datum_t *) datum;
+	if (cladatum == NULL) {
+		return 0;
+	}
+	(void)hashtab_map(cladatum->permissions.table, perm_destroy, 0);
+	hashtab_destroy(cladatum->permissions.table);
+	constraint = cladatum->constraints;
+	while (constraint) {
+		e = constraint->expr;
+		while (e) {
+			etmp = e;
+			e = e->next;
+			constraint_expr_destroy(etmp);
+		}
+		ctemp = constraint;
+		constraint = constraint->next;
+		free(ctemp);
+	}
+
+	constraint = cladatum->validatetrans;
+	while (constraint) {
+		e = constraint->expr;
+		while (e) {
+			etmp = e;
+			e = e->next;
+			constraint_expr_destroy(etmp);
+		}
+		ctemp = constraint;
+		constraint = constraint->next;
+		free(ctemp);
+	}
+
+	if (cladatum->comkey)
+		free(cladatum->comkey);
+	free(datum);
+	return 0;
+}
+
+static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			__attribute__ ((unused)))
+{
+	free(key);
+	role_datum_destroy((role_datum_t *) datum);
+	free(datum);
+	return 0;
+}
+
+static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			__attribute__ ((unused)))
+{
+	free(key);
+	type_datum_destroy((type_datum_t *) datum);
+	free(datum);
+	return 0;
+}
+
+static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			__attribute__ ((unused)))
+{
+	free(key);
+	user_datum_destroy((user_datum_t *) datum);
+	free(datum);
+	return 0;
+}
+
+static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+			__attribute__ ((unused)))
+{
+	level_datum_t *levdatum;
+
+	if (key)
+		free(key);
+	levdatum = (level_datum_t *) datum;
+	mls_level_destroy(levdatum->level);
+	free(levdatum->level);
+	level_datum_destroy(levdatum);
+	free(levdatum);
+	return 0;
+}
+
+static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+		       __attribute__ ((unused)))
+{
+	if (key)
+		free(key);
+	cat_datum_destroy((cat_datum_t *) datum);
+	free(datum);
+	return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+				  void *datap) = {
+common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
+	    cond_destroy_bool, sens_destroy, cat_destroy,};
+
+void ocontext_selinux_free(ocontext_t **ocontexts)
+{
+	ocontext_t *c, *ctmp;
+	int i;
+
+	for (i = 0; i < OCON_NUM; i++) {
+		c = ocontexts[i];
+		while (c) {
+			ctmp = c;
+			c = c->next;
+			context_destroy(&ctmp->context[0]);
+			context_destroy(&ctmp->context[1]);
+			if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF
+				|| i == OCON_FSUSE)
+				free(ctmp->u.name);
+			free(ctmp);
+		}
+	}
+}
+
+void ocontext_xen_free(ocontext_t **ocontexts)
+{
+	ocontext_t *c, *ctmp;
+	int i;
+
+	for (i = 0; i < OCON_NUM; i++) {
+		c = ocontexts[i];
+		while (c) {
+			ctmp = c;
+			c = c->next;
+			context_destroy(&ctmp->context[0]);
+			context_destroy(&ctmp->context[1]);
+			if (i == OCON_ISID || i == OCON_XEN_DEVICETREE)
+				free(ctmp->u.name);
+			free(ctmp);
+		}
+	}
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(policydb_t * p)
+{
+	ocontext_t *c, *ctmp;
+	genfs_t *g, *gtmp;
+	unsigned int i;
+	role_allow_t *ra, *lra = NULL;
+	role_trans_t *tr, *ltr = NULL;
+	range_trans_t *rt, *lrt = NULL;
+	filename_trans_t *ft, *nft;
+
+	if (!p)
+		return;
+
+	ebitmap_destroy(&p->policycaps);
+
+	ebitmap_destroy(&p->permissive_map);
+
+	symtabs_destroy(p->symtab);
+
+	for (i = 0; i < SYM_NUM; i++) {
+		if (p->sym_val_to_name[i])
+			free(p->sym_val_to_name[i]);
+	}
+
+	if (p->class_val_to_struct)
+		free(p->class_val_to_struct);
+	if (p->role_val_to_struct)
+		free(p->role_val_to_struct);
+	if (p->user_val_to_struct)
+		free(p->user_val_to_struct);
+	if (p->type_val_to_struct)
+		free(p->type_val_to_struct);
+	free(p->decl_val_to_struct);
+
+	for (i = 0; i < SYM_NUM; i++) {
+		(void)hashtab_map(p->scope[i].table, scope_destroy, 0);
+		hashtab_destroy(p->scope[i].table);
+	}
+	avrule_block_list_destroy(p->global);
+	free(p->name);
+	free(p->version);
+
+	avtab_destroy(&p->te_avtab);
+
+	if (p->target_platform == SEPOL_TARGET_SELINUX)
+		ocontext_selinux_free(p->ocontexts);
+	else if (p->target_platform == SEPOL_TARGET_XEN)
+		ocontext_xen_free(p->ocontexts);
+
+	g = p->genfs;
+	while (g) {
+		free(g->fstype);
+		c = g->head;
+		while (c) {
+			ctmp = c;
+			c = c->next;
+			context_destroy(&ctmp->context[0]);
+			free(ctmp->u.name);
+			free(ctmp);
+		}
+		gtmp = g;
+		g = g->next;
+		free(gtmp);
+	}
+	cond_policydb_destroy(p);
+
+	for (tr = p->role_tr; tr; tr = tr->next) {
+		if (ltr)
+			free(ltr);
+		ltr = tr;
+	}
+	if (ltr)
+		free(ltr);
+
+	ft = p->filename_trans;
+	while (ft) {
+		nft = ft->next;
+		free(ft->name);
+		free(ft);
+		ft = nft;
+	}
+
+	for (ra = p->role_allow; ra; ra = ra->next) {
+		if (lra)
+			free(lra);
+		lra = ra;
+	}
+	if (lra)
+		free(lra);
+
+	for (rt = p->range_tr; rt; rt = rt->next) {
+		if (lrt) {
+			ebitmap_destroy(&lrt->target_range.level[0].cat);
+			ebitmap_destroy(&lrt->target_range.level[1].cat);
+			free(lrt);
+		}
+		lrt = rt;
+	}
+	if (lrt) {
+		ebitmap_destroy(&lrt->target_range.level[0].cat);
+		ebitmap_destroy(&lrt->target_range.level[1].cat);
+		free(lrt);
+	}
+
+	if (p->type_attr_map) {
+		for (i = 0; i < p->p_types.nprim; i++) {
+			ebitmap_destroy(&p->type_attr_map[i]);
+		}
+		free(p->type_attr_map);
+	}
+
+	if (p->attr_type_map) {
+		for (i = 0; i < p->p_types.nprim; i++) {
+			ebitmap_destroy(&p->attr_type_map[i]);
+		}
+		free(p->attr_type_map);
+	}
+
+	return;
+}
+
+void symtabs_destroy(symtab_t * symtab)
+{
+	int i;
+	for (i = 0; i < SYM_NUM; i++) {
+		(void)hashtab_map(symtab[i].table, destroy_f[i], 0);
+		hashtab_destroy(symtab[i].table);
+	}
+}
+
+int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+		  __attribute__ ((unused)))
+{
+	scope_datum_t *cur = (scope_datum_t *) datum;
+	free(key);
+	if (cur != NULL) {
+		free(cur->decl_ids);
+	}
+	free(cur);
+	return 0;
+}
+
+hashtab_destroy_func_t get_symtab_destroy_func(int sym_num)
+{
+	if (sym_num < 0 || sym_num >= SYM_NUM) {
+		return NULL;
+	}
+	return (hashtab_destroy_func_t) destroy_f[sym_num];
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(policydb_t * p, sidtab_t * s)
+{
+	ocontext_t *head, *c;
+
+	if (sepol_sidtab_init(s)) {
+		ERR(NULL, "out of memory on SID table init");
+		return -1;
+	}
+
+	head = p->ocontexts[OCON_ISID];
+	for (c = head; c; c = c->next) {
+		if (!c->context[0].user) {
+			ERR(NULL, "SID %s was never defined", c->u.name);
+			return -1;
+		}
+		if (sepol_sidtab_insert(s, c->sid[0], &c->context[0])) {
+			ERR(NULL, "unable to load initial SID %s", c->u.name);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Declare a symbol for a certain avrule_block context.  Insert it
+ * into a symbol table for a policy.  This function will handle
+ * inserting the appropriate scope information in addition to
+ * inserting the symbol into the hash table.
+ *
+ * arguments:
+ *   policydb_t *pol       module policy to modify
+ *   uint32_t sym          the symbole table for insertion (SYM_*)
+ *   hashtab_key_t key     the key for the symbol - not cloned
+ *   hashtab_datum_t data  the data for the symbol - not cloned
+ *   scope                 scope of this symbol, either SCOPE_REQ or SCOPE_DECL
+ *   avrule_decl_id        identifier for this symbol's encapsulating declaration
+ *   value (out)           assigned value to the symbol (if value is not NULL)
+ *
+ * returns:
+ *   0                     success
+ *   1                     success, but symbol already existed as a requirement
+ *                         (datum was not inserted and needs to be free()d)
+ *   -1                    general error
+ *   -2                    scope conflicted
+ *   -ENOMEM               memory error
+ *   error codes from hashtab_insert
+ */
+int symtab_insert(policydb_t * pol, uint32_t sym,
+		  hashtab_key_t key, hashtab_datum_t datum,
+		  uint32_t scope, uint32_t avrule_decl_id, uint32_t * value)
+{
+	int rc, retval = 0;
+	unsigned int i;
+	scope_datum_t *scope_datum;
+
+	/* check if the symbol is already there.  multiple
+	 * declarations of non-roles/non-users are illegal, but
+	 * multiple requires are allowed. */
+
+	/* FIX ME - the failures after the hashtab_insert will leave
+	 * the policy in a inconsistent state. */
+	rc = hashtab_insert(pol->symtab[sym].table, key, datum);
+	if (rc == SEPOL_OK) {
+		/* if no value is passed in the symbol is not primary
+		 * (i.e. aliases) */
+		if (value)
+			*value = ++pol->symtab[sym].nprim;
+	} else if (rc == SEPOL_EEXIST) {
+		retval = 1;	/* symbol not added -- need to free() later */
+	} else {
+		return rc;
+	}
+
+	/* get existing scope information; if there is not one then
+	 * create it */
+	scope_datum =
+	    (scope_datum_t *) hashtab_search(pol->scope[sym].table, key);
+	if (scope_datum == NULL) {
+		hashtab_key_t key2 = strdup((char *)key);
+		if (!key2)
+			return -ENOMEM;
+		if ((scope_datum = malloc(sizeof(*scope_datum))) == NULL) {
+			free(key2);
+			return -ENOMEM;
+		}
+		scope_datum->scope = scope;
+		scope_datum->decl_ids = NULL;
+		scope_datum->decl_ids_len = 0;
+		if ((rc =
+		     hashtab_insert(pol->scope[sym].table, key2,
+				    scope_datum)) != 0) {
+			free(key2);
+			free(scope_datum);
+			return rc;
+		}
+	} else if (scope_datum->scope == SCOPE_DECL && scope == SCOPE_DECL) {
+		/* disallow multiple declarations for non-roles/users */
+		if (sym != SYM_ROLES && sym != SYM_USERS) {
+			return -2;
+		}
+		/* Further confine that a role attribute can't have the same
+		 * name as another regular role, and a role attribute can't
+		 * be declared more than once. */
+		if (sym == SYM_ROLES) {
+			role_datum_t *base_role;
+			role_datum_t *cur_role = (role_datum_t *)datum;
+		
+			base_role = (role_datum_t *)
+					hashtab_search(pol->symtab[sym].table,
+						       key);
+			assert(base_role != NULL);
+
+			if (!((base_role->flavor == ROLE_ROLE) &&
+			    (cur_role->flavor == ROLE_ROLE))) {
+				/* Only regular roles are allowed to have
+				 * multiple declarations. */
+				return -2;
+			}
+		}
+	} else if (scope_datum->scope == SCOPE_REQ && scope == SCOPE_DECL) {
+		scope_datum->scope = SCOPE_DECL;
+	} else if (scope_datum->scope != scope) {
+		/* This only happens in DECL then REQUIRE case, which is handled by caller */
+		return -2;
+	}
+
+	/* search through the pre-existing list to avoid adding duplicates */
+	for (i = 0; i < scope_datum->decl_ids_len; i++) {
+		if (scope_datum->decl_ids[i] == avrule_decl_id) {
+			/* already there, so don't modify its scope */
+			return retval;
+		}
+	}
+
+	if (add_i_to_a(avrule_decl_id,
+		       &scope_datum->decl_ids_len,
+		       &scope_datum->decl_ids) == -1) {
+		return -ENOMEM;
+	}
+
+	return retval;
+}
+
+int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b)
+{
+	type_set_init(dst);
+
+	if (ebitmap_or(&dst->types, &a->types, &b->types)) {
+		return -1;
+	}
+	if (ebitmap_or(&dst->negset, &a->negset, &b->negset)) {
+		return -1;
+	}
+
+	dst->flags |= a->flags;
+	dst->flags |= b->flags;
+
+	return 0;
+}
+
+int type_set_cpy(type_set_t * dst, type_set_t * src)
+{
+	type_set_init(dst);
+
+	dst->flags = src->flags;
+	if (ebitmap_cpy(&dst->types, &src->types))
+		return -1;
+	if (ebitmap_cpy(&dst->negset, &src->negset))
+		return -1;
+
+	return 0;
+}
+
+int type_set_or_eq(type_set_t * dst, type_set_t * other)
+{
+	int ret;
+	type_set_t tmp;
+
+	if (type_set_or(&tmp, dst, other))
+		return -1;
+	type_set_destroy(dst);
+	ret = type_set_cpy(dst, &tmp);
+	type_set_destroy(&tmp);
+
+	return ret;
+}
+
+int role_set_get_role(role_set_t * x, uint32_t role)
+{
+	if (x->flags & ROLE_STAR)
+		return 1;
+
+	if (ebitmap_get_bit(&x->roles, role - 1)) {
+		if (x->flags & ROLE_COMP)
+			return 0;
+		else
+			return 1;
+	} else {
+		if (x->flags & ROLE_COMP)
+			return 1;
+		else
+			return 0;
+	}
+}
+
+/***********************************************************************/
+/* everything below is for policy reads */
+
+/* The following are read functions for module structures */
+
+static int role_set_read(role_set_t * r, struct policy_file *fp)
+{
+	uint32_t buf[1];
+	int rc;
+
+	if (ebitmap_read(&r->roles, fp))
+		return -1;
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	r->flags = le32_to_cpu(buf[0]);
+
+	return 0;
+}
+
+static int type_set_read(type_set_t * t, struct policy_file *fp)
+{
+	uint32_t buf[1];
+	int rc;
+
+	if (ebitmap_read(&t->types, fp))
+		return -1;
+	if (ebitmap_read(&t->negset, fp))
+		return -1;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	t->flags = le32_to_cpu(buf[0]);
+
+	return 0;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary 
+ * representation file.
+ */
+static int mls_read_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+	uint32_t buf[2], items;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto out;
+
+	items = le32_to_cpu(buf[0]);
+	if (items > ARRAY_SIZE(buf)) {
+		ERR(fp->handle, "range overflow");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = next_entry(buf, fp, sizeof(uint32_t) * items);
+	if (rc < 0) {
+		ERR(fp->handle, "truncated range");
+		goto out;
+	}
+	r->level[0].sens = le32_to_cpu(buf[0]);
+	if (items > 1)
+		r->level[1].sens = le32_to_cpu(buf[1]);
+	else
+		r->level[1].sens = r->level[0].sens;
+
+	rc = ebitmap_read(&r->level[0].cat, fp);
+	if (rc) {
+		ERR(fp->handle, "error reading low categories");
+		goto out;
+	}
+	if (items > 1) {
+		rc = ebitmap_read(&r->level[1].cat, fp);
+		if (rc) {
+			ERR(fp->handle, "error reading high categories");
+			goto bad_high;
+		}
+	} else {
+		rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+		if (rc) {
+			ERR(fp->handle, "out of memory");
+			goto bad_high;
+		}
+	}
+
+	rc = 0;
+      out:
+	return rc;
+      bad_high:
+	ebitmap_destroy(&r->level[0].cat);
+	goto out;
+}
+
+/*
+ * Read a semantic MLS level structure from a policydb binary 
+ * representation file.
+ */
+static int mls_read_semantic_level_helper(mls_semantic_level_t * l,
+					  struct policy_file *fp)
+{
+	uint32_t buf[2], ncat;
+	unsigned int i;
+	mls_semantic_cat_t *cat;
+	int rc;
+
+	mls_semantic_level_init(l);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0) {
+		ERR(fp->handle, "truncated level");
+		goto bad;
+	}
+	l->sens = le32_to_cpu(buf[0]);
+
+	ncat = le32_to_cpu(buf[1]);
+	for (i = 0; i < ncat; i++) {
+		cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+		if (!cat) {
+			ERR(fp->handle, "out of memory");
+			goto bad;
+		}
+
+		mls_semantic_cat_init(cat);
+		cat->next = l->cat;
+		l->cat = cat;
+
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0) {
+			ERR(fp->handle, "error reading level categories");
+			goto bad;
+		}
+		cat->low = le32_to_cpu(buf[0]);
+		cat->high = le32_to_cpu(buf[1]);
+	}
+
+	return 0;
+
+      bad:
+	return -EINVAL;
+}
+
+/*
+ * Read a semantic MLS range structure from a policydb binary 
+ * representation file.
+ */
+static int mls_read_semantic_range_helper(mls_semantic_range_t * r,
+					  struct policy_file *fp)
+{
+	int rc;
+
+	rc = mls_read_semantic_level_helper(&r->level[0], fp);
+	if (rc)
+		return rc;
+
+	rc = mls_read_semantic_level_helper(&r->level[1], fp);
+
+	return rc;
+}
+
+static int mls_level_to_semantic(mls_level_t * l, mls_semantic_level_t * sl)
+{
+	unsigned int i;
+	ebitmap_node_t *cnode;
+	mls_semantic_cat_t *open_cat = NULL;
+
+	mls_semantic_level_init(sl);
+	sl->sens = l->sens;
+	ebitmap_for_each_bit(&l->cat, cnode, i) {
+		if (ebitmap_node_get_bit(cnode, i)) {
+			if (open_cat)
+				continue;
+			open_cat = (mls_semantic_cat_t *)
+			    malloc(sizeof(mls_semantic_cat_t));
+			if (!open_cat)
+				return -1;
+
+			mls_semantic_cat_init(open_cat);
+			open_cat->low = i + 1;
+			open_cat->next = sl->cat;
+			sl->cat = open_cat;
+		} else {
+			if (!open_cat)
+				continue;
+			open_cat->high = i;
+			open_cat = NULL;
+		}
+	}
+	if (open_cat)
+		open_cat->high = i;
+
+	return 0;
+}
+
+static int mls_range_to_semantic(mls_range_t * r, mls_semantic_range_t * sr)
+{
+	if (mls_level_to_semantic(&r->level[0], &sr->level[0]))
+		return -1;
+
+	if (mls_level_to_semantic(&r->level[1], &sr->level[1]))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(context_struct_t * c,
+				     policydb_t * p, struct policy_file *fp)
+{
+	uint32_t buf[3];
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+	if (rc < 0) {
+		ERR(fp->handle, "context truncated");
+		return -1;
+	}
+	c->user = le32_to_cpu(buf[0]);
+	c->role = le32_to_cpu(buf[1]);
+	c->type = le32_to_cpu(buf[2]);
+	if ((p->policy_type == POLICY_KERN
+	     && p->policyvers >= POLICYDB_VERSION_MLS)
+	    || (p->policy_type == POLICY_BASE
+		&& p->policyvers >= MOD_POLICYDB_VERSION_MLS)) {
+		if (mls_read_range_helper(&c->range, fp)) {
+			ERR(fp->handle, "error reading MLS range "
+			    "of context");
+			return -1;
+		}
+	}
+
+	if (!policydb_context_isvalid(p, c)) {
+		ERR(fp->handle, "invalid security context");
+		context_destroy(c);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(policydb_t * p
+		     __attribute__ ((unused)), hashtab_t h,
+		     struct policy_file *fp)
+{
+	char *key = 0;
+	perm_datum_t *perdatum;
+	uint32_t buf[2];
+	size_t len;
+	int rc;
+
+	perdatum = calloc(1, sizeof(perm_datum_t));
+	if (!perdatum)
+		return -1;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	perdatum->s.value = le32_to_cpu(buf[1]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (hashtab_insert(h, key, perdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	perm_destroy(key, perdatum, NULL);
+	return -1;
+}
+
+static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+	char *key = 0;
+	common_datum_t *comdatum;
+	uint32_t buf[4];
+	size_t len, nel;
+	unsigned int i;
+	int rc;
+
+	comdatum = calloc(1, sizeof(common_datum_t));
+	if (!comdatum)
+		return -1;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	comdatum->s.value = le32_to_cpu(buf[1]);
+
+	if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
+		goto bad;
+	comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+	nel = le32_to_cpu(buf[3]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	for (i = 0; i < nel; i++) {
+		if (perm_read(p, comdatum->permissions.table, fp))
+			goto bad;
+	}
+
+	if (hashtab_insert(h, key, comdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	common_destroy(key, comdatum, NULL);
+	return -1;
+}
+
+static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep,
+			    unsigned int ncons,
+			    int allowxtarget, struct policy_file *fp)
+{
+	constraint_node_t *c, *lc;
+	constraint_expr_t *e, *le;
+	uint32_t buf[3];
+	size_t nexpr;
+	unsigned int i, j;
+	int rc, depth;
+
+	lc = NULL;
+	for (i = 0; i < ncons; i++) {
+		c = calloc(1, sizeof(constraint_node_t));
+		if (!c)
+			return -1;
+
+		if (lc)
+			lc->next = c;
+		else
+			*nodep = c;
+
+		rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+		if (rc < 0)
+			return -1;
+		c->permissions = le32_to_cpu(buf[0]);
+		nexpr = le32_to_cpu(buf[1]);
+		le = NULL;
+		depth = -1;
+		for (j = 0; j < nexpr; j++) {
+			e = malloc(sizeof(constraint_expr_t));
+			if (!e)
+				return -1;
+			if (constraint_expr_init(e) == -1) {
+				free(e);
+				return -1;
+			}
+			if (le) {
+				le->next = e;
+			} else {
+				c->expr = e;
+			}
+
+			rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+			if (rc < 0)
+				return -1;
+			e->expr_type = le32_to_cpu(buf[0]);
+			e->attr = le32_to_cpu(buf[1]);
+			e->op = le32_to_cpu(buf[2]);
+
+			switch (e->expr_type) {
+			case CEXPR_NOT:
+				if (depth < 0)
+					return -1;
+				break;
+			case CEXPR_AND:
+			case CEXPR_OR:
+				if (depth < 1)
+					return -1;
+				depth--;
+				break;
+			case CEXPR_ATTR:
+				if (depth == (CEXPR_MAXDEPTH - 1))
+					return -1;
+				depth++;
+				break;
+			case CEXPR_NAMES:
+				if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+					return -1;
+				if (depth == (CEXPR_MAXDEPTH - 1))
+					return -1;
+				depth++;
+				if (ebitmap_read(&e->names, fp))
+					return -1;
+				if (p->policy_type != POLICY_KERN &&
+				    type_set_read(e->type_names, fp))
+					return -1;
+				else if (p->policy_type == POLICY_KERN &&
+					 p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
+					 type_set_read(e->type_names, fp))
+					return -1;
+				break;
+			default:
+				return -1;
+			}
+			le = e;
+		}
+		if (depth != 0)
+			return -1;
+		lc = c;
+	}
+
+	return 0;
+}
+
+static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+	char *key = 0;
+	class_datum_t *cladatum;
+	uint32_t buf[6];
+	size_t len, len2, ncons, nel;
+	unsigned int i;
+	int rc;
+
+	cladatum = (class_datum_t *) calloc(1, sizeof(class_datum_t));
+	if (!cladatum)
+		return -1;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 6);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	len2 = le32_to_cpu(buf[1]);
+	cladatum->s.value = le32_to_cpu(buf[2]);
+
+	if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
+		goto bad;
+	cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+	nel = le32_to_cpu(buf[4]);
+
+	ncons = le32_to_cpu(buf[5]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (len2) {
+		cladatum->comkey = malloc(len2 + 1);
+		if (!cladatum->comkey)
+			goto bad;
+		rc = next_entry(cladatum->comkey, fp, len2);
+		if (rc < 0)
+			goto bad;
+		cladatum->comkey[len2] = 0;
+
+		cladatum->comdatum = hashtab_search(p->p_commons.table,
+						    cladatum->comkey);
+		if (!cladatum->comdatum) {
+			ERR(fp->handle, "unknown common %s", cladatum->comkey);
+			goto bad;
+		}
+	}
+	for (i = 0; i < nel; i++) {
+		if (perm_read(p, cladatum->permissions.table, fp))
+			goto bad;
+	}
+
+	if (read_cons_helper(p, &cladatum->constraints, ncons, 0, fp))
+		goto bad;
+
+	if ((p->policy_type == POLICY_KERN
+	     && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+	    || (p->policy_type == POLICY_BASE
+		&& p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+		/* grab the validatetrans rules */
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+		ncons = le32_to_cpu(buf[0]);
+		if (read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp))
+			goto bad;
+	}
+
+	if ((p->policy_type == POLICY_KERN &&
+	     p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) ||
+	    (p->policy_type == POLICY_BASE &&
+	     p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) {
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+		if (rc < 0)
+			goto bad;
+		cladatum->default_user = le32_to_cpu(buf[0]);
+		cladatum->default_role = le32_to_cpu(buf[1]);
+		cladatum->default_range = le32_to_cpu(buf[2]);
+	}
+
+	if ((p->policy_type == POLICY_KERN &&
+	     p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
+	    (p->policy_type == POLICY_BASE &&
+	     p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+		cladatum->default_type = le32_to_cpu(buf[0]);
+	}
+
+	if (hashtab_insert(h, key, cladatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	class_destroy(key, cladatum, NULL);
+	return -1;
+}
+
+static int role_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+	char *key = 0;
+	role_datum_t *role;
+	uint32_t buf[3];
+	size_t len;
+	int rc, to_read = 2;
+
+	role = calloc(1, sizeof(role_datum_t));
+	if (!role)
+		return -1;
+
+	if (policydb_has_boundary_feature(p))
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	role->s.value = le32_to_cpu(buf[1]);
+	if (policydb_has_boundary_feature(p))
+		role->bounds = le32_to_cpu(buf[2]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (ebitmap_read(&role->dominates, fp))
+		goto bad;
+
+	if (p->policy_type == POLICY_KERN) {
+		if (ebitmap_read(&role->types.types, fp))
+			goto bad;
+	} else {
+		if (type_set_read(&role->types, fp))
+			goto bad;
+	}
+	
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+
+		role->flavor = le32_to_cpu(buf[0]);
+
+		if (ebitmap_read(&role->roles, fp))
+			goto bad;
+	}
+
+	if (strcmp(key, OBJECT_R) == 0) {
+		if (role->s.value != OBJECT_R_VAL) {
+			ERR(fp->handle, "role %s has wrong value %d",
+			    OBJECT_R, role->s.value);
+			role_destroy(key, role, NULL);
+			return -1;
+		}
+		role_destroy(key, role, NULL);
+		return 0;
+	}
+
+	if (hashtab_insert(h, key, role))
+		goto bad;
+
+	return 0;
+
+      bad:
+	role_destroy(key, role, NULL);
+	return -1;
+}
+
+static int type_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+	char *key = 0;
+	type_datum_t *typdatum;
+	uint32_t buf[5];
+	size_t len;
+	int rc, to_read;
+	int pos = 0;
+
+	typdatum = calloc(1, sizeof(type_datum_t));
+	if (!typdatum)
+		return -1;
+
+	if (policydb_has_boundary_feature(p)) {
+		if (p->policy_type != POLICY_KERN
+		    && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS)
+			to_read = 5;
+		else
+			to_read = 4;
+	}
+	else if (p->policy_type == POLICY_KERN)
+		to_read = 3;
+	else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+		to_read = 5;
+	else
+		to_read = 4;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[pos]);
+	typdatum->s.value = le32_to_cpu(buf[++pos]);
+	if (policydb_has_boundary_feature(p)) {
+		uint32_t properties;
+
+		if (p->policy_type != POLICY_KERN
+		    && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+			typdatum->primary = le32_to_cpu(buf[++pos]);
+			properties = le32_to_cpu(buf[++pos]);
+		}
+		else {
+			properties = le32_to_cpu(buf[++pos]);
+
+			if (properties & TYPEDATUM_PROPERTY_PRIMARY)
+				typdatum->primary = 1;
+		}
+
+		if (properties & TYPEDATUM_PROPERTY_ATTRIBUTE)
+			typdatum->flavor = TYPE_ATTRIB;
+		if (properties & TYPEDATUM_PROPERTY_ALIAS
+		    && p->policy_type != POLICY_KERN)
+			typdatum->flavor = TYPE_ALIAS;
+		if (properties & TYPEDATUM_PROPERTY_PERMISSIVE
+		    && p->policy_type != POLICY_KERN)
+			typdatum->flags |= TYPE_FLAGS_PERMISSIVE;
+
+		typdatum->bounds = le32_to_cpu(buf[++pos]);
+	} else {
+		typdatum->primary = le32_to_cpu(buf[++pos]);
+		if (p->policy_type != POLICY_KERN) {
+			typdatum->flavor = le32_to_cpu(buf[++pos]);
+			if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+				typdatum->flags = le32_to_cpu(buf[++pos]);
+		}
+	}
+
+	if (p->policy_type != POLICY_KERN) {
+		if (ebitmap_read(&typdatum->types, fp))
+			goto bad;
+	}
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (hashtab_insert(h, key, typdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	type_destroy(key, typdatum, NULL);
+	return -1;
+}
+
+int role_trans_read(policydb_t *p, struct policy_file *fp)
+{
+	role_trans_t **t = &p->role_tr;
+	unsigned int i;
+	uint32_t buf[3], nel;
+	role_trans_t *tr, *ltr;
+	int rc;
+	int new_roletr = (p->policy_type == POLICY_KERN &&
+			  p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	ltr = NULL;
+	for (i = 0; i < nel; i++) {
+		tr = calloc(1, sizeof(struct role_trans));
+		if (!tr) {
+			return -1;
+		}
+		if (ltr) {
+			ltr->next = tr;
+		} else {
+			*t = tr;
+		}
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+		if (rc < 0)
+			return -1;
+		tr->role = le32_to_cpu(buf[0]);
+		tr->type = le32_to_cpu(buf[1]);
+		tr->new_role = le32_to_cpu(buf[2]);
+		if (new_roletr) {
+			rc = next_entry(buf, fp, sizeof(uint32_t));
+			if (rc < 0)
+				return -1;
+			tr->tclass = le32_to_cpu(buf[0]);
+		} else
+			tr->tclass = SECCLASS_PROCESS;
+		ltr = tr;
+	}
+	return 0;
+}
+
+int role_allow_read(role_allow_t ** r, struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[2], nel;
+	role_allow_t *ra, *lra;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	lra = NULL;
+	for (i = 0; i < nel; i++) {
+		ra = calloc(1, sizeof(struct role_allow));
+		if (!ra) {
+			return -1;
+		}
+		if (lra) {
+			lra->next = ra;
+		} else {
+			*r = ra;
+		}
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0)
+			return -1;
+		ra->role = le32_to_cpu(buf[0]);
+		ra->new_role = le32_to_cpu(buf[1]);
+		lra = ra;
+	}
+	return 0;
+}
+
+int filename_trans_read(filename_trans_t **t, struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[4], nel, len;
+	filename_trans_t *ft, *lft;
+	int rc;
+	char *name;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+
+	lft = NULL;
+	for (i = 0; i < nel; i++) {
+		ft = calloc(1, sizeof(struct filename_trans));
+		if (!ft)
+			return -1;
+		if (lft)
+			lft->next = ft;
+		else
+			*t = ft;
+		lft = ft;
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+		len = le32_to_cpu(buf[0]);
+
+		name = calloc(len + 1, sizeof(*name));
+		if (!name)
+			return -1;
+
+		ft->name = name;
+
+		rc = next_entry(name, fp, len);
+		if (rc < 0)
+			return -1;
+
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+		if (rc < 0)
+			return -1;
+
+		ft->stype = le32_to_cpu(buf[0]);
+		ft->ttype = le32_to_cpu(buf[1]);
+		ft->tclass = le32_to_cpu(buf[2]);
+		ft->otype = le32_to_cpu(buf[3]);
+	}
+	return 0;
+}
+
+static int ocontext_read_xen(struct policydb_compat_info *info,
+	policydb_t *p, struct policy_file *fp)
+{
+	unsigned int i, j;
+	size_t nel, len;
+	ocontext_t *l, *c;
+	uint32_t buf[8];
+	int rc;
+
+	for (i = 0; i < info->ocon_num; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+		nel = le32_to_cpu(buf[0]);
+		l = NULL;
+		for (j = 0; j < nel; j++) {
+			c = calloc(1, sizeof(ocontext_t));
+			if (!c)
+				return -1;
+			if (l)
+				l->next = c;
+			else
+				p->ocontexts[i] = c;
+			l = c;
+			switch (i) {
+			case OCON_XEN_ISID:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				c->sid[0] = le32_to_cpu(buf[0]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_XEN_PIRQ:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				c->u.pirq = le32_to_cpu(buf[0]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_XEN_IOPORT:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+				if (rc < 0)
+					return -1;
+				c->u.ioport.low_ioport = le32_to_cpu(buf[0]);
+				c->u.ioport.high_ioport = le32_to_cpu(buf[1]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_XEN_IOMEM:
+				if (p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE) {
+					uint64_t b64[2];
+					rc = next_entry(b64, fp, sizeof(uint64_t) * 2);
+					if (rc < 0)
+						return -1;
+					c->u.iomem.low_iomem = le64_to_cpu(b64[0]);
+					c->u.iomem.high_iomem = le64_to_cpu(b64[1]);
+				} else {
+					rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+					if (rc < 0)
+						return -1;
+					c->u.iomem.low_iomem = le32_to_cpu(buf[0]);
+					c->u.iomem.high_iomem = le32_to_cpu(buf[1]);
+				}
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_XEN_PCIDEVICE:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				c->u.device = le32_to_cpu(buf[0]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_XEN_DEVICETREE:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				len = le32_to_cpu(buf[0]);
+				c->u.name = malloc(len + 1);
+				if (!c->u.name)
+					return -1;
+				rc = next_entry(c->u.name, fp, len);
+				if (rc < 0)
+					return -1;
+				c->u.name[len] = 0;
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			default:
+				/* should never get here */
+				ERR(fp->handle, "Unknown Xen ocontext");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+static int ocontext_read_selinux(struct policydb_compat_info *info,
+			 policydb_t * p, struct policy_file *fp)
+{
+	unsigned int i, j;
+	size_t nel, len;
+	ocontext_t *l, *c;
+	uint32_t buf[8];
+	int rc;
+
+	for (i = 0; i < info->ocon_num; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+		nel = le32_to_cpu(buf[0]);
+		l = NULL;
+		for (j = 0; j < nel; j++) {
+			c = calloc(1, sizeof(ocontext_t));
+			if (!c) {
+				return -1;
+			}
+			if (l) {
+				l->next = c;
+			} else {
+				p->ocontexts[i] = c;
+			}
+			l = c;
+			switch (i) {
+			case OCON_ISID:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				c->sid[0] = le32_to_cpu(buf[0]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_FS:
+			case OCON_NETIF:
+				rc = next_entry(buf, fp, sizeof(uint32_t));
+				if (rc < 0)
+					return -1;
+				len = le32_to_cpu(buf[0]);
+				c->u.name = malloc(len + 1);
+				if (!c->u.name)
+					return -1;
+				rc = next_entry(c->u.name, fp, len);
+				if (rc < 0)
+					return -1;
+				c->u.name[len] = 0;
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				if (context_read_and_validate
+				    (&c->context[1], p, fp))
+					return -1;
+				break;
+			case OCON_PORT:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+				if (rc < 0)
+					return -1;
+				c->u.port.protocol = le32_to_cpu(buf[0]);
+				c->u.port.low_port = le32_to_cpu(buf[1]);
+				c->u.port.high_port = le32_to_cpu(buf[2]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_NODE:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+				if (rc < 0)
+					return -1;
+				c->u.node.addr = buf[0]; /* network order */
+				c->u.node.mask = buf[1]; /* network order */
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_FSUSE:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+				if (rc < 0)
+					return -1;
+				c->v.behavior = le32_to_cpu(buf[0]);
+				len = le32_to_cpu(buf[1]);
+				c->u.name = malloc(len + 1);
+				if (!c->u.name)
+					return -1;
+				rc = next_entry(c->u.name, fp, len);
+				if (rc < 0)
+					return -1;
+				c->u.name[len] = 0;
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+			case OCON_NODE6:{
+				int k;
+
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 8);
+				if (rc < 0)
+					return -1;
+				for (k = 0; k < 4; k++)
+					 /* network order */
+					c->u.node6.addr[k] = buf[k];
+				for (k = 0; k < 4; k++)
+					/* network order */
+					c->u.node6.mask[k] = buf[k + 4];
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
+				}
+			default:{
+				ERR(fp->handle, "Unknown SELinux ocontext");
+				return -1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int ocontext_read(struct policydb_compat_info *info,
+	policydb_t *p, struct policy_file *fp)
+{
+	int rc = -1;
+	switch (p->target_platform) {
+	case SEPOL_TARGET_SELINUX:
+		rc = ocontext_read_selinux(info, p, fp);
+		break;
+	case SEPOL_TARGET_XEN:
+		rc = ocontext_read_xen(info, p, fp);
+		break;
+	default:
+		ERR(fp->handle, "Unknown target");
+	}
+	return rc;
+}
+
+static int genfs_read(policydb_t * p, struct policy_file *fp)
+{
+	uint32_t buf[1];
+	size_t nel, nel2, len, len2;
+	genfs_t *genfs_p, *newgenfs, *genfs;
+	unsigned int i, j;
+	ocontext_t *l, *c, *newc = NULL;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto bad;
+	nel = le32_to_cpu(buf[0]);
+	genfs_p = NULL;
+	for (i = 0; i < nel; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+		len = le32_to_cpu(buf[0]);
+		newgenfs = calloc(1, sizeof(genfs_t));
+		if (!newgenfs)
+			goto bad;
+		newgenfs->fstype = malloc(len + 1);
+		if (!newgenfs->fstype) {
+			free(newgenfs);
+			goto bad;
+		}
+		rc = next_entry(newgenfs->fstype, fp, len);
+		if (rc < 0) {
+			free(newgenfs->fstype);
+			free(newgenfs);
+			goto bad;
+		}
+		newgenfs->fstype[len] = 0;
+		for (genfs_p = NULL, genfs = p->genfs; genfs;
+		     genfs_p = genfs, genfs = genfs->next) {
+			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+				ERR(fp->handle, "dup genfs fstype %s",
+				    newgenfs->fstype);
+				free(newgenfs->fstype);
+				free(newgenfs);
+				goto bad;
+			}
+			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+				break;
+		}
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			p->genfs = newgenfs;
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			goto bad;
+		nel2 = le32_to_cpu(buf[0]);
+		for (j = 0; j < nel2; j++) {
+			newc = calloc(1, sizeof(ocontext_t));
+			if (!newc) {
+				goto bad;
+			}
+			rc = next_entry(buf, fp, sizeof(uint32_t));
+			if (rc < 0)
+				goto bad;
+			len = le32_to_cpu(buf[0]);
+			newc->u.name = malloc(len + 1);
+			if (!newc->u.name) {
+				goto bad;
+			}
+			rc = next_entry(newc->u.name, fp, len);
+			if (rc < 0)
+				goto bad;
+			newc->u.name[len] = 0;
+			rc = next_entry(buf, fp, sizeof(uint32_t));
+			if (rc < 0)
+				goto bad;
+			newc->v.sclass = le32_to_cpu(buf[0]);
+			if (context_read_and_validate(&newc->context[0], p, fp))
+				goto bad;
+			for (l = NULL, c = newgenfs->head; c;
+			     l = c, c = c->next) {
+				if (!strcmp(newc->u.name, c->u.name) &&
+				    (!c->v.sclass || !newc->v.sclass ||
+				     newc->v.sclass == c->v.sclass)) {
+					ERR(fp->handle, "dup genfs entry "
+					    "(%s,%s)", newgenfs->fstype,
+					    c->u.name);
+					goto bad;
+				}
+				len = strlen(newc->u.name);
+				len2 = strlen(c->u.name);
+				if (len > len2)
+					break;
+			}
+			newc->next = c;
+			if (l)
+				l->next = newc;
+			else
+				newgenfs->head = newc;
+		}
+	}
+
+	return 0;
+
+      bad:
+	if (newc) {
+		context_destroy(&newc->context[0]);
+		context_destroy(&newc->context[1]);
+		free(newc->u.name);
+		free(newc);
+	}
+	return -1;
+}
+
+/*
+ * Read a MLS level structure from a policydb binary 
+ * representation file.
+ */
+static int mls_read_level(mls_level_t * lp, struct policy_file *fp)
+{
+	uint32_t buf[1];
+	int rc;
+
+	mls_level_init(lp);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0) {
+		ERR(fp->handle, "truncated level");
+		goto bad;
+	}
+	lp->sens = le32_to_cpu(buf[0]);
+
+	if (ebitmap_read(&lp->cat, fp)) {
+		ERR(fp->handle, "error reading level categories");
+		goto bad;
+	}
+	return 0;
+
+      bad:
+	return -EINVAL;
+}
+
+static int user_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+	char *key = 0;
+	user_datum_t *usrdatum;
+	uint32_t buf[3];
+	size_t len;
+	int rc, to_read = 2;
+
+	usrdatum = calloc(1, sizeof(user_datum_t));
+	if (!usrdatum)
+		return -1;
+
+	if (policydb_has_boundary_feature(p))
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	usrdatum->s.value = le32_to_cpu(buf[1]);
+	if (policydb_has_boundary_feature(p))
+		usrdatum->bounds = le32_to_cpu(buf[2]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (p->policy_type == POLICY_KERN) {
+		if (ebitmap_read(&usrdatum->roles.roles, fp))
+			goto bad;
+	} else {
+		if (role_set_read(&usrdatum->roles, fp))
+			goto bad;
+	}
+
+	/* users were not allowed in mls modules before version
+	 * MOD_POLICYDB_VERSION_MLS_USERS, but they could have been
+	 * required - the mls fields will be empty.  user declarations in
+	 * non-mls modules will also have empty mls fields */
+	if ((p->policy_type == POLICY_KERN
+	     && p->policyvers >= POLICYDB_VERSION_MLS)
+	    || (p->policy_type == POLICY_MOD
+		&& p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)
+	    || (p->policy_type == POLICY_BASE
+		&& p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)) {
+		if (mls_read_range_helper(&usrdatum->exp_range, fp))
+			goto bad;
+		if (mls_read_level(&usrdatum->exp_dfltlevel, fp))
+			goto bad;
+		if (p->policy_type != POLICY_KERN) {
+			if (mls_range_to_semantic(&usrdatum->exp_range,
+						  &usrdatum->range))
+				goto bad;
+			if (mls_level_to_semantic(&usrdatum->exp_dfltlevel,
+						  &usrdatum->dfltlevel))
+				goto bad;
+		}
+	} else if ((p->policy_type == POLICY_MOD
+		    && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)
+		   || (p->policy_type == POLICY_BASE
+		       && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)) {
+		if (mls_read_semantic_range_helper(&usrdatum->range, fp))
+			goto bad;
+		if (mls_read_semantic_level_helper(&usrdatum->dfltlevel, fp))
+			goto bad;
+	}
+
+	if (hashtab_insert(h, key, usrdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	user_destroy(key, usrdatum, NULL);
+	return -1;
+}
+
+static int sens_read(policydb_t * p
+		     __attribute__ ((unused)), hashtab_t h,
+		     struct policy_file *fp)
+{
+	char *key = 0;
+	level_datum_t *levdatum;
+	uint32_t buf[2], len;
+	int rc;
+
+	levdatum = malloc(sizeof(level_datum_t));
+	if (!levdatum)
+		return -1;
+	level_datum_init(levdatum);
+
+	rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	levdatum->isalias = le32_to_cpu(buf[1]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	levdatum->level = malloc(sizeof(mls_level_t));
+	if (!levdatum->level || mls_read_level(levdatum->level, fp))
+		goto bad;
+
+	if (hashtab_insert(h, key, levdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	sens_destroy(key, levdatum, NULL);
+	return -1;
+}
+
+static int cat_read(policydb_t * p
+		    __attribute__ ((unused)), hashtab_t h,
+		    struct policy_file *fp)
+{
+	char *key = 0;
+	cat_datum_t *catdatum;
+	uint32_t buf[3], len;
+	int rc;
+
+	catdatum = malloc(sizeof(cat_datum_t));
+	if (!catdatum)
+		return -1;
+	cat_datum_init(catdatum);
+
+	rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+	if (rc < 0)
+		goto bad;
+
+	len = le32_to_cpu(buf[0]);
+	catdatum->s.value = le32_to_cpu(buf[1]);
+	catdatum->isalias = le32_to_cpu(buf[2]);
+
+	key = malloc(len + 1);
+	if (!key)
+		goto bad;
+	rc = next_entry(key, fp, len);
+	if (rc < 0)
+		goto bad;
+	key[len] = 0;
+
+	if (hashtab_insert(h, key, catdatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	cat_destroy(key, catdatum, NULL);
+	return -1;
+}
+
+static int (*read_f[SYM_NUM]) (policydb_t * p, hashtab_t h,
+			       struct policy_file * fp) = {
+common_read, class_read, role_read, type_read, user_read,
+	    cond_read_bool, sens_read, cat_read,};
+
+/************** module reading functions below **************/
+
+static avrule_t *avrule_read(policydb_t * p
+			     __attribute__ ((unused)), struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[2], len;
+	class_perm_node_t *cur, *tail = NULL;
+	avrule_t *avrule;
+	int rc;
+
+	avrule = (avrule_t *) malloc(sizeof(avrule_t));
+	if (!avrule)
+		return NULL;
+
+	avrule_init(avrule);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0)
+		goto bad;
+
+	(avrule)->specified = le32_to_cpu(buf[0]);
+	(avrule)->flags = le32_to_cpu(buf[1]);
+
+	if (type_set_read(&avrule->stypes, fp))
+		goto bad;
+
+	if (type_set_read(&avrule->ttypes, fp))
+		goto bad;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto bad;
+	len = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < len; i++) {
+		cur = (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+		if (!cur)
+			goto bad;
+		class_perm_node_init(cur);
+
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0) {
+			free(cur);
+			goto bad;
+		}
+
+		cur->tclass = le32_to_cpu(buf[0]);
+		cur->data = le32_to_cpu(buf[1]);
+
+		if (!tail) {
+			avrule->perms = cur;
+		} else {
+			tail->next = cur;
+		}
+		tail = cur;
+	}
+
+	return avrule;
+      bad:
+	if (avrule) {
+		avrule_destroy(avrule);
+		free(avrule);
+	}
+	return NULL;
+}
+
+static int range_read(policydb_t * p, struct policy_file *fp)
+{
+	uint32_t buf[2], nel;
+	range_trans_t *rt, *lrt;
+	range_trans_rule_t *rtr, *lrtr = NULL;
+	unsigned int i;
+	int new_rangetr = (p->policy_type == POLICY_KERN &&
+			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	lrt = NULL;
+	for (i = 0; i < nel; i++) {
+		rt = calloc(1, sizeof(range_trans_t));
+		if (!rt)
+			return -1;
+		if (lrt)
+			lrt->next = rt;
+		else
+			p->range_tr = rt;
+		rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+		if (rc < 0)
+			return -1;
+		rt->source_type = le32_to_cpu(buf[0]);
+		rt->target_type = le32_to_cpu(buf[1]);
+		if (new_rangetr) {
+			rc = next_entry(buf, fp, (sizeof(uint32_t)));
+			if (rc < 0)
+				return -1;
+			rt->target_class = le32_to_cpu(buf[0]);
+		} else
+			rt->target_class = SECCLASS_PROCESS;
+		if (mls_read_range_helper(&rt->target_range, fp))
+			return -1;
+		lrt = rt;
+	}
+
+	/* if this is a kernel policy, we are done - otherwise we need to
+	 * convert these structs to range_trans_rule_ts */
+	if (p->policy_type == POLICY_KERN)
+		return 0;
+
+	/* create range_trans_rules_ts that correspond to the range_trans_ts
+	 * that were just read in from an older policy */
+	for (rt = p->range_tr; rt; rt = rt->next) {
+		rtr = malloc(sizeof(range_trans_rule_t));
+		if (!rtr) {
+			return -1;
+		}
+		range_trans_rule_init(rtr);
+
+		if (lrtr)
+			lrtr->next = rtr;
+		else
+			p->global->enabled->range_tr_rules = rtr;
+
+		if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
+			return -1;
+
+		if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
+			return -1;
+
+		if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
+			return -1;
+
+		if (mls_range_to_semantic(&rt->target_range, &rtr->trange))
+			return -1;
+
+		lrtr = rtr;
+	}
+
+	/* now destroy the range_trans_ts */
+	lrt = NULL;
+	for (rt = p->range_tr; rt; rt = rt->next) {
+		if (lrt) {
+			ebitmap_destroy(&lrt->target_range.level[0].cat);
+			ebitmap_destroy(&lrt->target_range.level[1].cat);
+			free(lrt);
+		}
+		lrt = rt;
+	}
+	if (lrt) {
+		ebitmap_destroy(&lrt->target_range.level[0].cat);
+		ebitmap_destroy(&lrt->target_range.level[1].cat);
+		free(lrt);
+	}
+	p->range_tr = NULL;
+
+	return 0;
+}
+
+int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+		     struct policy_file *fp)
+{
+	unsigned int i;
+	avrule_t *cur, *tail;
+	uint32_t buf[1], len;
+	int rc;
+
+	*avrules = tail = NULL;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0) {
+		return -1;
+	}
+	len = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < len; i++) {
+		cur = avrule_read(p, fp);
+		if (!cur) {
+			return -1;
+		}
+
+		if (!tail) {
+			*avrules = cur;
+		} else {
+			tail->next = cur;
+		}
+		tail = cur;
+	}
+
+	return 0;
+}
+
+static int role_trans_rule_read(policydb_t *p, role_trans_rule_t ** r,
+				struct policy_file *fp)
+{
+	uint32_t buf[1], nel;
+	unsigned int i;
+	role_trans_rule_t *tr, *ltr;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	ltr = NULL;
+	for (i = 0; i < nel; i++) {
+		tr = malloc(sizeof(role_trans_rule_t));
+		if (!tr) {
+			return -1;
+		}
+		role_trans_rule_init(tr);
+
+		if (ltr) {
+			ltr->next = tr;
+		} else {
+			*r = tr;
+		}
+
+		if (role_set_read(&tr->roles, fp))
+			return -1;
+
+		if (type_set_read(&tr->types, fp))
+			return -1;
+
+		if (p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS) {
+			if (ebitmap_read(&tr->classes, fp))
+				return -1;
+		} else {
+			if (ebitmap_set_bit(&tr->classes, SECCLASS_PROCESS - 1, 1))
+				return -1;
+		}
+
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+		tr->new_role = le32_to_cpu(buf[0]);
+		ltr = tr;
+	}
+
+	return 0;
+}
+
+static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[1], nel;
+	role_allow_rule_t *ra, *lra;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	lra = NULL;
+	for (i = 0; i < nel; i++) {
+		ra = malloc(sizeof(role_allow_rule_t));
+		if (!ra) {
+			return -1;
+		}
+		role_allow_rule_init(ra);
+
+		if (lra) {
+			lra->next = ra;
+		} else {
+			*r = ra;
+		}
+
+		if (role_set_read(&ra->roles, fp))
+			return -1;
+
+		if (role_set_read(&ra->new_roles, fp))
+			return -1;
+
+		lra = ra;
+	}
+	return 0;
+}
+
+static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_file *fp)
+{
+	uint32_t buf[2], nel;
+	unsigned int i, len;
+	filename_trans_rule_t *ftr, *lftr;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	lftr = NULL;
+	for (i = 0; i < nel; i++) {
+		ftr = malloc(sizeof(*ftr));
+		if (!ftr)
+			return -1;
+
+		filename_trans_rule_init(ftr);
+
+		if (lftr)
+			lftr->next = ftr;
+		else
+			*r = ftr;
+		lftr = ftr;
+
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+
+		len = le32_to_cpu(buf[0]);
+
+		ftr->name = malloc(len + 1);
+		if (!ftr->name)
+			return -1;
+
+		rc = next_entry(ftr->name, fp, len);
+		if (rc)
+			return -1;
+		ftr->name[len] = 0;
+
+		if (type_set_read(&ftr->stypes, fp))
+			return -1;
+
+		if (type_set_read(&ftr->ttypes, fp))
+			return -1;
+
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0)
+			return -1;
+		ftr->tclass = le32_to_cpu(buf[0]);
+		ftr->otype = le32_to_cpu(buf[1]);
+	}
+
+	return 0;
+}
+
+static int range_trans_rule_read(range_trans_rule_t ** r,
+				 struct policy_file *fp)
+{
+	uint32_t buf[1], nel;
+	unsigned int i;
+	range_trans_rule_t *rt, *lrt = NULL;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	nel = le32_to_cpu(buf[0]);
+	for (i = 0; i < nel; i++) {
+		rt = malloc(sizeof(range_trans_rule_t));
+		if (!rt) {
+			return -1;
+		}
+		range_trans_rule_init(rt);
+
+		if (lrt)
+			lrt->next = rt;
+		else
+			*r = rt;
+
+		if (type_set_read(&rt->stypes, fp))
+			return -1;
+
+		if (type_set_read(&rt->ttypes, fp))
+			return -1;
+
+		if (ebitmap_read(&rt->tclasses, fp))
+			return -1;
+
+		if (mls_read_semantic_range_helper(&rt->trange, fp))
+			return -1;
+
+		lrt = rt;
+	}
+
+	return 0;
+}
+
+static int scope_index_read(scope_index_t * scope_index,
+			    unsigned int num_scope_syms, struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[1];
+	int rc;
+
+	for (i = 0; i < num_scope_syms; i++) {
+		if (ebitmap_read(scope_index->scope + i, fp) == -1) {
+			return -1;
+		}
+	}
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	scope_index->class_perms_len = le32_to_cpu(buf[0]);
+	if (scope_index->class_perms_len == 0) {
+		scope_index->class_perms_map = NULL;
+		return 0;
+	}
+	if ((scope_index->class_perms_map =
+	     calloc(scope_index->class_perms_len,
+		    sizeof(*scope_index->class_perms_map))) == NULL) {
+		return -1;
+	}
+	for (i = 0; i < scope_index->class_perms_len; i++) {
+		if (ebitmap_read(scope_index->class_perms_map + i, fp) == -1) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
+			    unsigned int num_scope_syms, struct policy_file *fp)
+{
+	uint32_t buf[2], nprim, nel;
+	unsigned int i, j;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0)
+		return -1;
+	decl->decl_id = le32_to_cpu(buf[0]);
+	decl->enabled = le32_to_cpu(buf[1]);
+	if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
+	    avrule_read_list(p, &decl->avrules, fp) == -1 ||
+	    role_trans_rule_read(p, &decl->role_tr_rules, fp) == -1 ||
+	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
+		return -1;
+	}
+
+	if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+	    filename_trans_rule_read(&decl->filename_trans_rules, fp))
+		return -1;
+
+	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+	    range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
+		return -1;
+	}
+	if (scope_index_read(&decl->required, num_scope_syms, fp) == -1 ||
+	    scope_index_read(&decl->declared, num_scope_syms, fp) == -1) {
+		return -1;
+	}
+
+	for (i = 0; i < num_scope_syms; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0) 
+			return -1;
+		nprim = le32_to_cpu(buf[0]);
+		nel = le32_to_cpu(buf[1]);
+		for (j = 0; j < nel; j++) {
+			if (read_f[i] (p, decl->symtab[i].table, fp)) {
+				return -1;
+			}
+		}
+		decl->symtab[i].nprim = nprim;
+	}
+	return 0;
+}
+
+static int avrule_block_read(policydb_t * p,
+			     avrule_block_t ** block,
+			     unsigned int num_scope_syms,
+			     struct policy_file *fp)
+{
+	avrule_block_t *last_block = NULL, *curblock;
+	uint32_t buf[1], num_blocks, nel;
+	int rc;
+
+	assert(*block == NULL);
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		return -1;
+	num_blocks = le32_to_cpu(buf[0]);
+	nel = num_blocks;
+	while (num_blocks > 0) {
+		avrule_decl_t *last_decl = NULL, *curdecl;
+		uint32_t num_decls;
+		if ((curblock = calloc(1, sizeof(*curblock))) == NULL) {
+			return -1;
+		}
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0) {
+			free(curblock);
+			return -1;
+		}
+		/* if this is the first block its non-optional, else its optional */
+		if (num_blocks != nel)
+			curblock->flags |= AVRULE_OPTIONAL;
+
+		num_decls = le32_to_cpu(buf[0]);
+		while (num_decls > 0) {
+			if ((curdecl = avrule_decl_create(0)) == NULL) {
+				avrule_block_destroy(curblock);
+				return -1;
+			}
+			if (avrule_decl_read(p, curdecl, num_scope_syms, fp) ==
+			    -1) {
+				avrule_decl_destroy(curdecl);
+				avrule_block_destroy(curblock);
+				return -1;
+			}
+			if (curdecl->enabled) {
+				if (curblock->enabled != NULL) {
+					/* probably a corrupt file */
+					avrule_decl_destroy(curdecl);
+					avrule_block_destroy(curblock);
+					return -1;
+				}
+				curblock->enabled = curdecl;
+			}
+			/* one must be careful to reconstruct the
+			 * decl chain in its correct order */
+			if (curblock->branch_list == NULL) {
+				curblock->branch_list = curdecl;
+			} else {
+				assert(last_decl);
+				last_decl->next = curdecl;
+			}
+			last_decl = curdecl;
+			num_decls--;
+		}
+
+		if (*block == NULL) {
+			*block = curblock;
+		} else {
+			assert(last_block);
+			last_block->next = curblock;
+		}
+		last_block = curblock;
+
+		num_blocks--;
+	}
+
+	return 0;
+}
+
+static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
+{
+	scope_datum_t *scope = NULL;
+	uint32_t buf[2];
+	char *key = NULL;
+	size_t key_len;
+	unsigned int i;
+	hashtab_t h = p->scope[symnum].table;
+	int rc;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t));
+	if (rc < 0)
+		goto cleanup;
+	key_len = le32_to_cpu(buf[0]);
+	key = malloc(key_len + 1);
+	if (!key)
+		goto cleanup;
+	rc = next_entry(key, fp, key_len);
+	if (rc < 0)
+		goto cleanup;
+	key[key_len] = '\0';
+
+	/* ensure that there already exists a symbol with this key */
+	if (hashtab_search(p->symtab[symnum].table, key) == NULL) {
+		goto cleanup;
+	}
+
+	if ((scope = calloc(1, sizeof(*scope))) == NULL) {
+		goto cleanup;
+	}
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0)
+		goto cleanup;
+	scope->scope = le32_to_cpu(buf[0]);
+	scope->decl_ids_len = le32_to_cpu(buf[1]);
+	assert(scope->decl_ids_len > 0);
+	if ((scope->decl_ids =
+	     malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) {
+		goto cleanup;
+	}
+	rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len);
+	if (rc < 0)
+		goto cleanup;
+	for (i = 0; i < scope->decl_ids_len; i++) {
+		scope->decl_ids[i] = le32_to_cpu(scope->decl_ids[i]);
+	}
+
+	if (strcmp(key, "object_r") == 0 && h == p->p_roles_scope.table) {
+		/* object_r was already added to this table in roles_init() */
+		scope_destroy(key, scope, NULL);
+	} else {
+		if (hashtab_insert(h, key, scope)) {
+			goto cleanup;
+		}
+	}
+
+	return 0;
+
+      cleanup:
+	scope_destroy(key, scope, NULL);
+	return -1;
+}
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
+{
+
+	unsigned int i, j, r_policyvers;
+	uint32_t buf[5];
+	size_t len, nprim, nel;
+	char *policydb_str;
+	struct policydb_compat_info *info;
+	unsigned int policy_type, bufindex;
+	ebitmap_node_t *tnode;
+	int rc;
+
+	/* Read the magic number and string length. */
+	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (rc < 0)
+		return POLICYDB_ERROR;
+	for (i = 0; i < 2; i++)
+		buf[i] = le32_to_cpu(buf[i]);
+
+	if (buf[0] == POLICYDB_MAGIC) {
+		policy_type = POLICY_KERN;
+	} else if (buf[0] == POLICYDB_MOD_MAGIC) {
+		policy_type = POLICY_MOD;
+	} else {
+		ERR(fp->handle, "policydb magic number %#08x does not "
+		    "match expected magic number %#08x or %#08x",
+		    buf[0], POLICYDB_MAGIC, POLICYDB_MOD_MAGIC);
+		return POLICYDB_ERROR;
+	}
+
+	len = buf[1];
+	if (len > POLICYDB_STRING_MAX_LENGTH) {
+		ERR(fp->handle, "policydb string length too long ");
+		return POLICYDB_ERROR;
+	}
+
+	policydb_str = malloc(len + 1);
+	if (!policydb_str) {
+		ERR(fp->handle, "unable to allocate memory for policydb "
+		    "string of length %zu", len);
+		return POLICYDB_ERROR;
+	}
+	rc = next_entry(policydb_str, fp, len);
+	if (rc < 0) {
+		ERR(fp->handle, "truncated policydb string identifier");
+		free(policydb_str);
+		return POLICYDB_ERROR;
+	}
+	policydb_str[len] = 0;
+
+	if (policy_type == POLICY_KERN) {
+		for (i = 0; i < POLICYDB_TARGET_SZ; i++) {
+			if ((strcmp(policydb_str, policydb_target_strings[i])
+				== 0)) {
+				policydb_set_target_platform(p, i);
+				break;
+			}
+		}
+
+		if (i == POLICYDB_TARGET_SZ) {
+			ERR(fp->handle, "cannot find a valid target for policy "
+				"string %s", policydb_str);
+			free(policydb_str);
+			return POLICYDB_ERROR;
+		}
+	} else {
+		if (strcmp(policydb_str, POLICYDB_MOD_STRING)) {
+			ERR(fp->handle, "invalid string identifier %s",
+				policydb_str);
+			free(policydb_str);
+			return POLICYDB_ERROR;
+		}
+	}
+
+	/* Done with policydb_str. */
+	free(policydb_str);
+	policydb_str = NULL;
+
+	/* Read the version, config, and table sizes (and policy type if it's a module). */
+	if (policy_type == POLICY_KERN)
+		nel = 4;
+	else
+		nel = 5;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * nel);
+	if (rc < 0)
+		return POLICYDB_ERROR;
+	for (i = 0; i < nel; i++)
+		buf[i] = le32_to_cpu(buf[i]);
+
+	bufindex = 0;
+
+	if (policy_type == POLICY_MOD) {
+		/* We know it's a module but not whether it's a base
+		   module or regular binary policy module.  buf[0]
+		   tells us which. */
+		policy_type = buf[bufindex];
+		if (policy_type != POLICY_MOD && policy_type != POLICY_BASE) {
+			ERR(fp->handle, "unknown module type: %#08x",
+			    policy_type);
+			return POLICYDB_ERROR;
+		}
+		bufindex++;
+	}
+
+	r_policyvers = buf[bufindex];
+	if (policy_type == POLICY_KERN) {
+		if (r_policyvers < POLICYDB_VERSION_MIN ||
+		    r_policyvers > POLICYDB_VERSION_MAX) {
+			ERR(fp->handle, "policydb version %d does not match "
+			    "my version range %d-%d", buf[bufindex],
+			    POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+			return POLICYDB_ERROR;
+		}
+	} else if (policy_type == POLICY_BASE || policy_type == POLICY_MOD) {
+		if (r_policyvers < MOD_POLICYDB_VERSION_MIN ||
+		    r_policyvers > MOD_POLICYDB_VERSION_MAX) {
+			ERR(fp->handle, "policydb module version %d does "
+			    "not match my version range %d-%d",
+			    buf[bufindex], MOD_POLICYDB_VERSION_MIN,
+			    MOD_POLICYDB_VERSION_MAX);
+			return POLICYDB_ERROR;
+		}
+	} else {
+		assert(0);
+	}
+	bufindex++;
+
+	/* Set the policy type and version from the read values. */
+	p->policy_type = policy_type;
+	p->policyvers = r_policyvers;
+
+	if (buf[bufindex] & POLICYDB_CONFIG_MLS) {
+		p->mls = 1;
+	} else {
+		p->mls = 0;
+	}
+
+	p->handle_unknown = buf[bufindex] & POLICYDB_CONFIG_UNKNOWN_MASK;
+
+	bufindex++;
+
+	info = policydb_lookup_compat(r_policyvers, policy_type,
+					p->target_platform);
+	if (!info) {
+		ERR(fp->handle, "unable to find policy compat info "
+		    "for version %d", r_policyvers);
+		goto bad;
+	}
+
+	if (buf[bufindex] != info->sym_num
+	    || buf[bufindex + 1] != info->ocon_num) {
+		ERR(fp->handle,
+		    "policydb table sizes (%d,%d) do not " "match mine (%d,%d)",
+		    buf[bufindex], buf[bufindex + 1], info->sym_num,
+		    info->ocon_num);
+		goto bad;
+	}
+
+	if (p->policy_type == POLICY_MOD) {
+		/* Get the module name and version */
+		if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+			goto bad;
+		}
+		len = le32_to_cpu(buf[0]);
+		if ((p->name = malloc(len + 1)) == NULL) {
+			goto bad;
+		}
+		if ((rc = next_entry(p->name, fp, len)) < 0) {
+			goto bad;
+		}
+		p->name[len] = '\0';
+		if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+			goto bad;
+		}
+		len = le32_to_cpu(buf[0]);
+		if ((p->version = malloc(len + 1)) == NULL) {
+			goto bad;
+		}
+		if ((rc = next_entry(p->version, fp, len)) < 0) {
+			goto bad;
+		}
+		p->version[len] = '\0';
+	}
+
+	if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_KERN) ||
+	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_BASE) ||
+	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_MOD)) {
+		if (ebitmap_read(&p->policycaps, fp))
+			goto bad;
+	}
+
+	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+	    p->policy_type == POLICY_KERN) {
+		if (ebitmap_read(&p->permissive_map, fp))
+			goto bad;
+	}
+
+	for (i = 0; i < info->sym_num; i++) {
+		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+		if (rc < 0)
+			goto bad;
+		nprim = le32_to_cpu(buf[0]);
+		nel = le32_to_cpu(buf[1]);
+		for (j = 0; j < nel; j++) {
+			if (read_f[i] (p, p->symtab[i].table, fp))
+				goto bad;
+		}
+
+		p->symtab[i].nprim = nprim;
+	}
+
+	if (policy_type == POLICY_KERN) {
+		if (avtab_read(&p->te_avtab, fp, r_policyvers))
+			goto bad;
+		if (r_policyvers >= POLICYDB_VERSION_BOOL)
+			if (cond_read_list(p, &p->cond_list, fp))
+				goto bad;
+		if (role_trans_read(p, fp))
+			goto bad;
+		if (role_allow_read(&p->role_allow, fp))
+			goto bad;
+		if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
+		    filename_trans_read(&p->filename_trans, fp))
+			goto bad;
+	} else {
+		/* first read the AV rule blocks, then the scope tables */
+		avrule_block_destroy(p->global);
+		p->global = NULL;
+		if (avrule_block_read(p, &p->global, info->sym_num, fp) == -1) {
+			goto bad;
+		}
+		for (i = 0; i < info->sym_num; i++) {
+			if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+				goto bad;
+			}
+			nel = le32_to_cpu(buf[0]);
+			for (j = 0; j < nel; j++) {
+				if (scope_read(p, i, fp))
+					goto bad;
+			}
+		}
+
+	}
+
+	if (policydb_index_decls(p))
+		goto bad;
+
+	if (policydb_index_classes(p))
+		goto bad;
+
+	if (policydb_index_others(fp->handle, p, verbose))
+		goto bad;
+
+	if (ocontext_read(info, p, fp) == -1) {
+		goto bad;
+	}
+
+	if (genfs_read(p, fp) == -1) {
+		goto bad;
+	}
+
+	if ((p->policy_type == POLICY_KERN
+	     && p->policyvers >= POLICYDB_VERSION_MLS)
+	    || (p->policy_type == POLICY_BASE
+		&& p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS)) {
+		if (range_read(p, fp)) {
+			goto bad;
+		}
+	}
+
+	if (policy_type == POLICY_KERN) {
+		p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+		p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+		if (!p->type_attr_map || !p->attr_type_map)
+			goto bad;
+		for (i = 0; i < p->p_types.nprim; i++) {
+			ebitmap_init(&p->type_attr_map[i]);
+			ebitmap_init(&p->attr_type_map[i]);
+		}
+		for (i = 0; i < p->p_types.nprim; i++) {
+			if (r_policyvers >= POLICYDB_VERSION_AVTAB) {
+				if (ebitmap_read(&p->type_attr_map[i], fp))
+					goto bad;
+				ebitmap_for_each_bit(&p->type_attr_map[i],
+						     tnode, j) {
+					if (!ebitmap_node_get_bit(tnode, j)
+					    || i == j)
+						continue;
+					if (ebitmap_set_bit
+					    (&p->attr_type_map[j], i, 1))
+						goto bad;
+				}
+			}
+			/* add the type itself as the degenerate case */
+			if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+				goto bad;
+			if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
+				if (ebitmap_set_bit(&p->attr_type_map[i], i, 1))
+					goto bad;
+			}
+		}
+	}
+
+	return POLICYDB_SUCCESS;
+      bad:
+	return POLICYDB_ERROR;
+}
+
+int policydb_reindex_users(policydb_t * p)
+{
+	unsigned int i = SYM_USERS;
+
+	if (p->user_val_to_struct)
+		free(p->user_val_to_struct);
+	if (p->sym_val_to_name[i])
+		free(p->sym_val_to_name[i]);
+
+	p->user_val_to_struct = (user_datum_t **)
+	    malloc(p->p_users.nprim * sizeof(user_datum_t *));
+	if (!p->user_val_to_struct)
+		return -1;
+
+	p->sym_val_to_name[i] = (char **)
+	    malloc(p->symtab[i].nprim * sizeof(char *));
+	if (!p->sym_val_to_name[i])
+		return -1;
+
+	if (hashtab_map(p->symtab[i].table, index_f[i], p))
+		return -1;
+
+	/* Expand user roles for context validity checking */
+	if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+		return -1;
+
+	return 0;
+}
+
+void policy_file_init(policy_file_t *pf)
+{
+	memset(pf, 0, sizeof(policy_file_t));
+}
+
+int policydb_set_target_platform(policydb_t *p, int platform)
+{
+	if (platform == SEPOL_TARGET_SELINUX)
+		p->target_platform = SEPOL_TARGET_SELINUX;
+	else if (platform == SEPOL_TARGET_XEN)
+		p->target_platform = SEPOL_TARGET_XEN;
+	else
+		return -1;
+
+	return 0;
+}
+
diff --git a/libsepol/src/policydb_convert.c b/libsepol/src/policydb_convert.c
new file mode 100644
index 0000000..3fc40cb
--- /dev/null
+++ b/libsepol/src/policydb_convert.c
@@ -0,0 +1,101 @@
+#include <stdlib.h>
+
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/policydb/policydb.h>
+
+/* Construct a policydb from the supplied (data, len) pair */
+
+int policydb_from_image(sepol_handle_t * handle,
+			void *data, size_t len, policydb_t * policydb)
+{
+
+	policy_file_t pf;
+
+	policy_file_init(&pf);
+	pf.type = PF_USE_MEMORY;
+	pf.data = data;
+	pf.len = len;
+	pf.handle = handle;
+
+	if (policydb_read(policydb, &pf, 0)) {
+		policydb_destroy(policydb);
+		ERR(handle, "policy image is invalid");
+		errno = EINVAL;
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+/* Write a policydb to a memory region, and return the (data, len) pair. */
+
+int policydb_to_image(sepol_handle_t * handle,
+		      policydb_t * policydb, void **newdata, size_t * newlen)
+{
+
+	void *tmp_data = NULL;
+	size_t tmp_len;
+	policy_file_t pf;
+	struct policydb tmp_policydb;
+
+	/* Compute the length for the new policy image. */
+	policy_file_init(&pf);
+	pf.type = PF_LEN;
+	pf.handle = handle;
+	if (policydb_write(policydb, &pf)) {
+		ERR(handle, "could not compute policy length");
+		errno = EINVAL;
+		goto err;
+	}
+
+	/* Allocate the new policy image. */
+	pf.type = PF_USE_MEMORY;
+	pf.data = malloc(pf.len);
+	if (!pf.data) {
+		ERR(handle, "out of memory");
+		goto err;
+	}
+
+	/* Need to save len and data prior to modification by policydb_write. */
+	tmp_len = pf.len;
+	tmp_data = pf.data;
+
+	/* Write out the new policy image. */
+	if (policydb_write(policydb, &pf)) {
+		ERR(handle, "could not write policy");
+		errno = EINVAL;
+		goto err;
+	}
+
+	/* Verify the new policy image. */
+	pf.type = PF_USE_MEMORY;
+	pf.data = tmp_data;
+	pf.len = tmp_len;
+	if (policydb_init(&tmp_policydb)) {
+		ERR(handle, "Out of memory");
+		errno = ENOMEM;
+		goto err;
+	}
+	if (policydb_read(&tmp_policydb, &pf, 0)) {
+		ERR(handle, "new policy image is invalid");
+		errno = EINVAL;
+		goto err;
+	}
+	policydb_destroy(&tmp_policydb);
+
+	/* Update (newdata, newlen) */
+	*newdata = tmp_data;
+	*newlen = tmp_len;
+
+	/* Recover */
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not create policy image");
+
+	/* Recover */
+	free(tmp_data);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/policydb_internal.h b/libsepol/src/policydb_internal.h
new file mode 100644
index 0000000..f7bcdfa
--- /dev/null
+++ b/libsepol/src/policydb_internal.h
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_POLICYDB_INTERNAL_H_
+#define _SEPOL_POLICYDB_INTERNAL_H_
+
+#include <sepol/policydb.h>
+#include "dso.h"
+
+hidden_proto(sepol_policydb_create)
+    hidden_proto(sepol_policydb_free)
+extern const char *policydb_target_strings[];
+#endif
diff --git a/libsepol/src/policydb_public.c b/libsepol/src/policydb_public.c
new file mode 100644
index 0000000..e721842
--- /dev/null
+++ b/libsepol/src/policydb_public.c
@@ -0,0 +1,210 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include <sepol/policydb/policydb.h>
+#include "policydb_internal.h"
+
+/* Policy file interfaces. */
+
+int sepol_policy_file_create(sepol_policy_file_t ** pf)
+{
+	*pf = calloc(1, sizeof(sepol_policy_file_t));
+	if (!(*pf))
+		return -1;
+	return 0;
+}
+
+void sepol_policy_file_set_mem(sepol_policy_file_t * spf,
+			       char *data, size_t len)
+{
+	struct policy_file *pf = &spf->pf;
+	if (!len) {
+		pf->type = PF_LEN;
+		return;
+	}
+	pf->type = PF_USE_MEMORY;
+	pf->data = data;
+	pf->len = len;
+	pf->size = len;
+	return;
+}
+
+void sepol_policy_file_set_fp(sepol_policy_file_t * spf, FILE * fp)
+{
+	struct policy_file *pf = &spf->pf;
+	pf->type = PF_USE_STDIO;
+	pf->fp = fp;
+	return;
+}
+
+int sepol_policy_file_get_len(sepol_policy_file_t * spf, size_t * len)
+{
+	struct policy_file *pf = &spf->pf;
+	if (pf->type != PF_LEN)
+		return -1;
+	*len = pf->len;
+	return 0;
+}
+
+void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+				  sepol_handle_t * handle)
+{
+	pf->pf.handle = handle;
+}
+
+void sepol_policy_file_free(sepol_policy_file_t * pf)
+{
+	free(pf);
+}
+
+/* Policydb interfaces. */
+
+int sepol_policydb_create(sepol_policydb_t ** sp)
+{
+	policydb_t *p;
+	*sp = malloc(sizeof(sepol_policydb_t));
+	if (!(*sp))
+		return -1;
+	p = &(*sp)->p;
+	if (policydb_init(p)) {
+		free(*sp);
+		return -1;
+	}
+	return 0;
+}
+
+hidden_def(sepol_policydb_create)
+
+void sepol_policydb_free(sepol_policydb_t * p)
+{
+	if (!p)
+		return;
+	policydb_destroy(&p->p);
+	free(p);
+}
+
+hidden_def(sepol_policydb_free)
+
+int sepol_policy_kern_vers_min(void)
+{
+	return POLICYDB_VERSION_MIN;
+}
+
+int sepol_policy_kern_vers_max(void)
+{
+	return POLICYDB_VERSION_MAX;
+}
+
+int sepol_policydb_set_typevers(sepol_policydb_t * sp, unsigned int type)
+{
+	struct policydb *p = &sp->p;
+	switch (type) {
+	case POLICY_KERN:
+		p->policyvers = POLICYDB_VERSION_MAX;
+		break;
+	case POLICY_BASE:
+	case POLICY_MOD:
+		p->policyvers = MOD_POLICYDB_VERSION_MAX;
+		break;
+	default:
+		return -1;
+	}
+	p->policy_type = type;
+	return 0;
+}
+
+int sepol_policydb_set_vers(sepol_policydb_t * sp, unsigned int vers)
+{
+	struct policydb *p = &sp->p;
+	switch (p->policy_type) {
+	case POLICY_KERN:
+		if (vers < POLICYDB_VERSION_MIN || vers > POLICYDB_VERSION_MAX)
+			return -1;
+		break;
+	case POLICY_BASE:
+	case POLICY_MOD:
+		if (vers < MOD_POLICYDB_VERSION_MIN
+		    || vers > MOD_POLICYDB_VERSION_MAX)
+			return -1;
+		break;
+	default:
+		return -1;
+	}
+	p->policyvers = vers;
+	return 0;
+}
+
+int sepol_policydb_set_handle_unknown(sepol_policydb_t * sp,
+				      unsigned int handle_unknown)
+{
+	struct policydb *p = &sp->p;
+
+	switch (handle_unknown) {
+	case SEPOL_DENY_UNKNOWN:
+	case SEPOL_REJECT_UNKNOWN:
+	case SEPOL_ALLOW_UNKNOWN:
+		break;
+	default:
+		return -1;
+	}
+
+	p->handle_unknown = handle_unknown;		
+	return 0;
+}
+
+int sepol_policydb_set_target_platform(sepol_policydb_t * sp,
+				      int target_platform)
+{
+	struct policydb *p = &sp->p;
+
+	switch (target_platform) {
+	case SEPOL_TARGET_SELINUX:
+	case SEPOL_TARGET_XEN:
+		break;
+	default:
+		return -1;
+	}
+
+	p->target_platform = target_platform;		
+	return 0;
+}
+
+int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+	return policydb_read(&p->p, &pf->pf, 0);
+}
+
+int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+	return policydb_write(&p->p, &pf->pf);
+}
+
+int sepol_policydb_from_image(sepol_handle_t * handle,
+			      void *data, size_t len, sepol_policydb_t * p)
+{
+	return policydb_from_image(handle, data, len, &p->p);
+}
+
+int sepol_policydb_to_image(sepol_handle_t * handle,
+			    sepol_policydb_t * p, void **newdata,
+			    size_t * newlen)
+{
+	return policydb_to_image(handle, &p->p, newdata, newlen);
+}
+
+int sepol_policydb_mls_enabled(const sepol_policydb_t * p)
+{
+
+	return p->p.mls;
+}
+
+/* 
+ * Enable compatibility mode for SELinux network checks iff
+ * the packet class is not defined in the policy.
+ */
+#define PACKET_CLASS_NAME "packet"
+int sepol_policydb_compat_net(const sepol_policydb_t * p)
+{
+	return (hashtab_search(p->p.p_classes.table, PACKET_CLASS_NAME) ==
+		NULL);
+}
diff --git a/libsepol/src/port_internal.h b/libsepol/src/port_internal.h
new file mode 100644
index 0000000..ffb5f65
--- /dev/null
+++ b/libsepol/src/port_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_PORT_INTERNAL_H_
+#define _SEPOL_PORT_INTERNAL_H_
+
+#include <sepol/port_record.h>
+#include <sepol/ports.h>
+#include "dso.h"
+
+hidden_proto(sepol_port_create)
+    hidden_proto(sepol_port_free)
+    hidden_proto(sepol_port_get_con)
+    hidden_proto(sepol_port_get_high)
+    hidden_proto(sepol_port_get_low)
+    hidden_proto(sepol_port_get_proto)
+    hidden_proto(sepol_port_get_proto_str)
+    hidden_proto(sepol_port_key_create)
+    hidden_proto(sepol_port_key_unpack)
+    hidden_proto(sepol_port_set_con)
+    hidden_proto(sepol_port_set_proto)
+    hidden_proto(sepol_port_set_range)
+#endif
diff --git a/libsepol/src/port_record.c b/libsepol/src/port_record.c
new file mode 100644
index 0000000..ed9093b
--- /dev/null
+++ b/libsepol/src/port_record.c
@@ -0,0 +1,290 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_port {
+	/* Low - High range. Same for single ports. */
+	int low, high;
+
+	/* Protocol */
+	int proto;
+
+	/* Context */
+	sepol_context_t *con;
+};
+
+struct sepol_port_key {
+	/* Low - High range. Same for single ports. */
+	int low, high;
+
+	/* Protocol */
+	int proto;
+};
+
+/* Key */
+int sepol_port_key_create(sepol_handle_t * handle,
+			  int low, int high, int proto,
+			  sepol_port_key_t ** key_ptr)
+{
+
+	sepol_port_key_t *tmp_key =
+	    (sepol_port_key_t *) malloc(sizeof(sepol_port_key_t));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, could not create " "port key");
+		return STATUS_ERR;
+	}
+
+	tmp_key->low = low;
+	tmp_key->high = high;
+	tmp_key->proto = proto;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_key_create)
+
+void sepol_port_key_unpack(const sepol_port_key_t * key,
+			   int *low, int *high, int *proto)
+{
+
+	*low = key->low;
+	*high = key->high;
+	*proto = key->proto;
+}
+
+hidden_def(sepol_port_key_unpack)
+
+int sepol_port_key_extract(sepol_handle_t * handle,
+			   const sepol_port_t * port,
+			   sepol_port_key_t ** key_ptr)
+{
+
+	if (sepol_port_key_create
+	    (handle, port->low, port->high, port->proto, key_ptr) < 0) {
+
+		ERR(handle, "could not extract key from port %s %d:%d",
+		    sepol_port_get_proto_str(port->proto),
+		    port->low, port->high);
+
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_port_key_free(sepol_port_key_t * key)
+{
+	free(key);
+}
+
+int sepol_port_compare(const sepol_port_t * port, const sepol_port_key_t * key)
+{
+
+	if ((port->low == key->low) &&
+	    (port->high == key->high) && (port->proto == key->proto))
+		return 0;
+
+	if (port->low < key->low)
+		return -1;
+
+	else if (key->low < port->low)
+		return 1;
+
+	else if (port->high < key->high)
+		return -1;
+
+	else if (key->high < port->high)
+		return 1;
+
+	else if (port->proto < key->proto)
+		return -1;
+
+	else
+		return 1;
+}
+
+int sepol_port_compare2(const sepol_port_t * port, const sepol_port_t * port2)
+{
+
+	if ((port->low == port2->low) &&
+	    (port->high == port2->high) && (port->proto == port2->proto))
+		return 0;
+
+	if (port->low < port2->low)
+		return -1;
+
+	else if (port2->low < port->low)
+		return 1;
+
+	else if (port->high < port2->high)
+		return -1;
+
+	else if (port2->high < port->high)
+		return 1;
+
+	else if (port->proto < port2->proto)
+		return -1;
+
+	else
+		return 1;
+}
+
+/* Port */
+int sepol_port_get_low(const sepol_port_t * port)
+{
+
+	return port->low;
+}
+
+hidden_def(sepol_port_get_low)
+
+int sepol_port_get_high(const sepol_port_t * port)
+{
+
+	return port->high;
+}
+
+hidden_def(sepol_port_get_high)
+
+void sepol_port_set_port(sepol_port_t * port, int port_num)
+{
+
+	port->low = port_num;
+	port->high = port_num;
+}
+
+void sepol_port_set_range(sepol_port_t * port, int low, int high)
+{
+
+	port->low = low;
+	port->high = high;
+}
+
+hidden_def(sepol_port_set_range)
+
+/* Protocol */
+int sepol_port_get_proto(const sepol_port_t * port)
+{
+
+	return port->proto;
+}
+
+hidden_def(sepol_port_get_proto)
+
+const char *sepol_port_get_proto_str(int proto)
+{
+
+	switch (proto) {
+	case SEPOL_PROTO_UDP:
+		return "udp";
+	case SEPOL_PROTO_TCP:
+		return "tcp";
+	case SEPOL_PROTO_DCCP:
+		return "dccp";
+	default:
+		return "???";
+	}
+}
+
+hidden_def(sepol_port_get_proto_str)
+
+void sepol_port_set_proto(sepol_port_t * port, int proto)
+{
+
+	port->proto = proto;
+}
+
+hidden_def(sepol_port_set_proto)
+
+/* Create */
+int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port)
+{
+
+	sepol_port_t *tmp_port = (sepol_port_t *) malloc(sizeof(sepol_port_t));
+
+	if (!tmp_port) {
+		ERR(handle, "out of memory, could not create " "port record");
+		return STATUS_ERR;
+	}
+
+	tmp_port->low = 0;
+	tmp_port->high = 0;
+	tmp_port->proto = SEPOL_PROTO_UDP;
+	tmp_port->con = NULL;
+	*port = tmp_port;
+
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_create)
+
+/* Deep copy clone */
+int sepol_port_clone(sepol_handle_t * handle,
+		     const sepol_port_t * port, sepol_port_t ** port_ptr)
+{
+
+	sepol_port_t *new_port = NULL;
+	if (sepol_port_create(handle, &new_port) < 0)
+		goto err;
+
+	new_port->low = port->low;
+	new_port->high = port->high;
+	new_port->proto = port->proto;
+
+	if (port->con &&
+	    (sepol_context_clone(handle, port->con, &new_port->con) < 0))
+		goto err;
+
+	*port_ptr = new_port;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not clone port record");
+	sepol_port_free(new_port);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_port_free(sepol_port_t * port)
+{
+
+	if (!port)
+		return;
+
+	sepol_context_free(port->con);
+	free(port);
+}
+
+hidden_def(sepol_port_free)
+
+/* Context */
+sepol_context_t *sepol_port_get_con(const sepol_port_t * port)
+{
+
+	return port->con;
+}
+
+hidden_def(sepol_port_get_con)
+
+int sepol_port_set_con(sepol_handle_t * handle,
+		       sepol_port_t * port, sepol_context_t * con)
+{
+
+	sepol_context_t *newcon;
+
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set port context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(port->con);
+	port->con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_set_con)
diff --git a/libsepol/src/ports.c b/libsepol/src/ports.c
new file mode 100644
index 0000000..62ec602
--- /dev/null
+++ b/libsepol/src/ports.c
@@ -0,0 +1,318 @@
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "port_internal.h"
+
+static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
+{
+
+	switch (proto) {
+	case SEPOL_PROTO_TCP:
+		return IPPROTO_TCP;
+	case SEPOL_PROTO_UDP:
+		return IPPROTO_UDP;
+	case SEPOL_PROTO_DCCP:
+		return IPPROTO_DCCP;
+	default:
+		ERR(handle, "unsupported protocol %u", proto);
+		return STATUS_ERR;
+	}
+}
+
+static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
+{
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		return SEPOL_PROTO_TCP;
+	case IPPROTO_UDP:
+		return SEPOL_PROTO_UDP;
+	case IPPROTO_DCCP:
+		return SEPOL_PROTO_DCCP;
+	default:
+		ERR(handle, "invalid protocol %u " "found in policy", proto);
+		return STATUS_ERR;
+	}
+}
+
+/* Create a low level port structure from
+ * a high level representation */
+static int port_from_record(sepol_handle_t * handle,
+			    const policydb_t * policydb,
+			    ocontext_t ** port, const sepol_port_t * data)
+{
+
+	ocontext_t *tmp_port = NULL;
+	context_struct_t *tmp_con = NULL;
+	int tmp_proto;
+
+	int low = sepol_port_get_low(data);
+	int high = sepol_port_get_high(data);
+	int proto = sepol_port_get_proto(data);
+
+	tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+	if (!tmp_port)
+		goto omem;
+
+	/* Process protocol */
+	tmp_proto = sepol2ipproto(handle, proto);
+	if (tmp_proto < 0)
+		goto err;
+	tmp_port->u.port.protocol = tmp_proto;
+
+	/* Port range */
+	tmp_port->u.port.low_port = low;
+	tmp_port->u.port.high_port = high;
+	if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
+		ERR(handle, "low port %d exceeds high port %d",
+		    tmp_port->u.port.low_port, tmp_port->u.port.high_port);
+		goto err;
+	}
+
+	/* Context */
+	if (context_from_record(handle, policydb, &tmp_con,
+				sepol_port_get_con(data)) < 0)
+		goto err;
+	context_cpy(&tmp_port->context[0], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	*port = tmp_port;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	if (tmp_port != NULL) {
+		context_destroy(&tmp_port->context[0]);
+		free(tmp_port);
+	}
+	context_destroy(tmp_con);
+	free(tmp_con);
+	ERR(handle, "could not create port structure for range %u:%u (%s)",
+	    low, high, sepol_port_get_proto_str(proto));
+	return STATUS_ERR;
+}
+
+static int port_to_record(sepol_handle_t * handle,
+			  const policydb_t * policydb,
+			  ocontext_t * port, sepol_port_t ** record)
+{
+
+	int proto = port->u.port.protocol;
+	int low = port->u.port.low_port;
+	int high = port->u.port.high_port;
+	context_struct_t *con = &port->context[0];
+	int rec_proto = -1;
+
+	sepol_context_t *tmp_con = NULL;
+	sepol_port_t *tmp_record = NULL;
+
+	if (sepol_port_create(handle, &tmp_record) < 0)
+		goto err;
+
+	rec_proto = ipproto2sepol(handle, proto);
+	if (rec_proto < 0)
+		goto err;
+
+	sepol_port_set_proto(tmp_record, rec_proto);
+	sepol_port_set_range(tmp_record, low, high);
+
+	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+		goto err;
+
+	if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
+		goto err;
+
+	sepol_context_free(tmp_con);
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not convert port range %u - %u (%s) "
+	    "to record", low, high, sepol_port_get_proto_str(rec_proto));
+	sepol_context_free(tmp_con);
+	sepol_port_free(tmp_record);
+	return STATUS_ERR;
+}
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
+			    const sepol_policydb_t * p, unsigned int *response)
+{
+
+	unsigned int count = 0;
+	ocontext_t *c, *head;
+	const policydb_t *policydb = &p->p;
+
+	head = policydb->ocontexts[OCON_PORT];
+	for (c = head; c != NULL; c = c->next)
+		count++;
+
+	*response = count;
+
+	return STATUS_SUCCESS;
+}
+
+/* Check if a port exists */
+int sepol_port_exists(sepol_handle_t * handle,
+		      const sepol_policydb_t * p,
+		      const sepol_port_key_t * key, int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	int low, high, proto;
+	const char *proto_str;
+	sepol_port_key_unpack(key, &low, &high, &proto);
+	proto_str = sepol_port_get_proto_str(proto);
+	proto = sepol2ipproto(handle, proto);
+	if (proto < 0)
+		goto err;
+
+	head = policydb->ocontexts[OCON_PORT];
+	for (c = head; c; c = c->next) {
+		int proto2 = c->u.port.protocol;
+		int low2 = c->u.port.low_port;
+		int high2 = c->u.port.high_port;
+
+		if (proto == proto2 && low2 == low && high2 == high) {
+			*response = 1;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = 0;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not check if port range %u - %u (%s) exists",
+	    low, high, proto_str);
+	return STATUS_ERR;
+}
+
+/* Query a port */
+int sepol_port_query(sepol_handle_t * handle,
+		     const sepol_policydb_t * p,
+		     const sepol_port_key_t * key, sepol_port_t ** response)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+
+	int low, high, proto;
+	const char *proto_str;
+	sepol_port_key_unpack(key, &low, &high, &proto);
+	proto_str = sepol_port_get_proto_str(proto);
+	proto = sepol2ipproto(handle, proto);
+	if (proto < 0)
+		goto err;
+
+	head = policydb->ocontexts[OCON_PORT];
+	for (c = head; c; c = c->next) {
+		int proto2 = c->u.port.protocol;
+		int low2 = c->u.port.low_port;
+		int high2 = c->u.port.high_port;
+
+		if (proto == proto2 && low2 == low && high2 == high) {
+			if (port_to_record(handle, policydb, c, response) < 0)
+				goto err;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = NULL;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not query port range %u - %u (%s)",
+	    low, high, proto_str);
+	return STATUS_ERR;
+
+}
+
+/* Load a port into policy */
+int sepol_port_modify(sepol_handle_t * handle,
+		      sepol_policydb_t * p,
+		      const sepol_port_key_t * key, const sepol_port_t * data)
+{
+
+	policydb_t *policydb = &p->p;
+	ocontext_t *port = NULL;
+
+	int low, high, proto;
+	const char *proto_str;
+
+	sepol_port_key_unpack(key, &low, &high, &proto);
+	proto_str = sepol_port_get_proto_str(proto);
+	proto = sepol2ipproto(handle, proto);
+	if (proto < 0)
+		goto err;
+
+	if (port_from_record(handle, policydb, &port, data) < 0)
+		goto err;
+
+	/* Attach to context list */
+	port->next = policydb->ocontexts[OCON_PORT];
+	policydb->ocontexts[OCON_PORT] = port;
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not load port range %u - %u (%s)",
+	    low, high, proto_str);
+	if (port != NULL) {
+		context_destroy(&port->context[0]);
+		free(port);
+	}
+	return STATUS_ERR;
+}
+
+int sepol_port_iterate(sepol_handle_t * handle,
+		       const sepol_policydb_t * p,
+		       int (*fn) (const sepol_port_t * port,
+				  void *fn_arg), void *arg)
+{
+
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	sepol_port_t *port = NULL;
+
+	head = policydb->ocontexts[OCON_PORT];
+	for (c = head; c; c = c->next) {
+		int status;
+
+		if (port_to_record(handle, policydb, c, &port) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(port, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_port_free(port);
+		port = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not iterate over ports");
+	sepol_port_free(port);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/private.h b/libsepol/src/private.h
new file mode 100644
index 0000000..9c700c9
--- /dev/null
+++ b/libsepol/src/private.h
@@ -0,0 +1,64 @@
+/* Private definitions for libsepol. */
+
+/* Endian conversion for reading and writing binary policies */
+
+#include <sepol/policydb/policydb.h>
+
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#else
+#include <byteswap.h>
+#include <endian.h>
+#endif
+
+#include <errno.h>
+#include <dso.h>
+
+#ifdef __APPLE__
+#define __BYTE_ORDER  BYTE_ORDER
+#define __LITTLE_ENDIAN  LITTLE_ENDIAN
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+#define le64_to_cpu(x) (x)
+#else
+#define cpu_to_le16(x) bswap_16(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#define le64_to_cpu(x) bswap_64(x)
+#endif
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+#undef max
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+/* Policy compatibility information. */
+struct policydb_compat_info {
+	unsigned int type;
+	unsigned int version;
+	unsigned int sym_num;
+	unsigned int ocon_num;
+	unsigned int target_platform;
+};
+
+extern struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+							   unsigned int type,
+						unsigned int target_platform);
+
+/* Reading from a policy "file". */
+extern int next_entry(void *buf, struct policy_file *fp, size_t bytes) hidden;
+extern size_t put_entry(const void *ptr, size_t size, size_t n,
+		        struct policy_file *fp) hidden;
diff --git a/libsepol/src/roles.c b/libsepol/src/roles.c
new file mode 100644
index 0000000..713d834
--- /dev/null
+++ b/libsepol/src/roles.c
@@ -0,0 +1,54 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "handle.h"
+
+/* Check if a role exists */
+int sepol_role_exists(sepol_handle_t * handle __attribute__ ((unused)),
+		      sepol_policydb_t * p, const char *role, int *response)
+{
+
+	policydb_t *policydb = &p->p;
+	*response = (hashtab_search(policydb->p_roles.table,
+				    (const hashtab_key_t)role) != NULL);
+
+	return STATUS_SUCCESS;
+}
+
+/* Fill an array with all valid roles */
+int sepol_role_list(sepol_handle_t * handle,
+		    sepol_policydb_t * p, char ***roles, unsigned int *nroles)
+{
+
+	policydb_t *policydb = &p->p;
+	unsigned int tmp_nroles = policydb->p_roles.nprim;
+	char **tmp_roles = (char **)malloc(tmp_nroles * sizeof(char *));
+	char **ptr;
+	unsigned int i;
+	if (!tmp_roles)
+		goto omem;
+
+	for (i = 0; i < tmp_nroles; i++) {
+		tmp_roles[i] = strdup(policydb->p_role_val_to_name[i]);
+		if (!tmp_roles[i])
+			goto omem;
+	}
+
+	*nroles = tmp_nroles;
+	*roles = tmp_roles;
+
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not list roles");
+
+	ptr = tmp_roles;
+	while (ptr && *ptr)
+		free(*ptr++);
+	free(tmp_roles);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
new file mode 100644
index 0000000..d64a8e8
--- /dev/null
+++ b/libsepol/src/services.c
@@ -0,0 +1,2171 @@
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com>
+ *          and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc.  James Morris <jmorris@redhat.com>
+ *
+ *      Fine-grained netlink support
+ *      IPv6 support
+ *      Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ *  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
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the security services.
+ */
+
+/* Initial sizes malloc'd for sepol_compute_av_reason_buffer() support */
+#define REASON_BUF_SIZE 2048
+#define EXPR_BUF_SIZE 1024
+#define STACK_LEN 32
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/sidtab.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+#include "private.h"
+#include "context.h"
+#include "av_permissions.h"
+#include "dso.h"
+#include "mls.h"
+
+#define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+#define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+
+static int selinux_enforcing = 1;
+
+static sidtab_t mysidtab, *sidtab = &mysidtab;
+static policydb_t mypolicydb, *policydb = &mypolicydb;
+
+/* Used by sepol_compute_av_reason_buffer() to keep track of entries */
+static int reason_buf_used;
+static int reason_buf_len;
+
+/* Stack services for RPN to infix conversion. */
+static char **stack;
+static int stack_len;
+static int next_stack_entry;
+
+static void push(char *expr_ptr)
+{
+	if (next_stack_entry >= stack_len) {
+		char **new_stack = stack;
+		int new_stack_len;
+
+		if (stack_len == 0)
+			new_stack_len = STACK_LEN;
+		else
+			new_stack_len = stack_len * 2;
+
+		new_stack = realloc(stack, new_stack_len * sizeof(*stack));
+		if (!new_stack) {
+			ERR(NULL, "unable to allocate stack space");
+			return;
+		}
+		stack_len = new_stack_len;
+		stack = new_stack;
+	}
+	stack[next_stack_entry] = expr_ptr;
+	next_stack_entry++;
+}
+
+static char *pop(void)
+{
+	next_stack_entry--;
+	if (next_stack_entry < 0) {
+		next_stack_entry = 0;
+		ERR(NULL, "pop called with no stack entries");
+		return NULL;
+	}
+	return stack[next_stack_entry];
+}
+/* End Stack services */
+
+int hidden sepol_set_sidtab(sidtab_t * s)
+{
+	sidtab = s;
+	return 0;
+}
+
+int hidden sepol_set_policydb(policydb_t * p)
+{
+	policydb = p;
+	return 0;
+}
+
+int sepol_set_policydb_from_file(FILE * fp)
+{
+	struct policy_file pf;
+
+	policy_file_init(&pf);
+	pf.fp = fp;
+	pf.type = PF_USE_STDIO;
+	if (mypolicydb.policy_type)
+		policydb_destroy(&mypolicydb);
+	if (policydb_init(&mypolicydb)) {
+		ERR(NULL, "Out of memory!");
+		return -1;
+	}
+	if (policydb_read(&mypolicydb, &pf, 0)) {
+		policydb_destroy(&mypolicydb);
+		ERR(NULL, "can't read binary policy: %s", strerror(errno));
+		return -1;
+	}
+	policydb = &mypolicydb;
+	return sepol_sidtab_init(sidtab);
+}
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static uint32_t latest_granting = 0;
+
+/*
+ * cat_expr_buf adds a string to an expression buffer and handles
+ * realloc's if buffer is too small. The array of expression text
+ * buffer pointers and its counter are globally defined here as
+ * constraint_expr_eval_reason() sets them up and cat_expr_buf
+ * updates the e_buf pointer.
+ */
+static int expr_counter;
+static char **expr_list;
+static int expr_buf_used;
+static int expr_buf_len;
+
+static void cat_expr_buf(char *e_buf, const char *string)
+{
+	int len, new_buf_len;
+	char *p, *new_buf = e_buf;
+
+	while (1) {
+		p = e_buf + expr_buf_used;
+		len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string);
+		if (len < 0 || len >= expr_buf_len - expr_buf_used) {
+			new_buf_len = expr_buf_len + EXPR_BUF_SIZE;
+			new_buf = realloc(e_buf, new_buf_len);
+			if (!new_buf) {
+				ERR(NULL, "failed to realloc expr buffer");
+				return;
+			}
+			/* Update new ptr in expr list and locally + new len */
+			expr_list[expr_counter] = new_buf;
+			e_buf = new_buf;
+			expr_buf_len = new_buf_len;
+		} else {
+			expr_buf_used += len;
+			return;
+		}
+	}
+}
+
+/*
+ * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES,
+ * then for 'types' only, read the types_names->types list as it will
+ * contain a list of types and attributes that were defined in the
+ * policy source.
+ * For user and role plus types (for policy vers <
+ * POLICYDB_VERSION_CONSTRAINT_NAMES) just read the e->names list.
+ */
+static void get_name_list(constraint_expr_t *e, int type,
+							const char *src, const char *op, int failed)
+{
+	ebitmap_t *types;
+	int rc = 0;
+	unsigned int i;
+	char tmp_buf[128];
+	int counter = 0;
+
+	if (policydb->policy_type == POLICY_KERN &&
+			policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
+			type == CEXPR_TYPE)
+		types = &e->type_names->types;
+	else
+		types = &e->names;
+
+	/* Find out how many entries */
+	for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
+		rc = ebitmap_get_bit(types, i);
+		if (rc == 0)
+			continue;
+		else
+			counter++;
+	}
+	snprintf(tmp_buf, sizeof(tmp_buf), "(%s%s", src, op);
+	cat_expr_buf(expr_list[expr_counter], tmp_buf);
+
+	if (counter == 0)
+		cat_expr_buf(expr_list[expr_counter], "<empty_set> ");
+	if (counter > 1)
+		cat_expr_buf(expr_list[expr_counter], " {");
+	if (counter >= 1) {
+		for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
+			rc = ebitmap_get_bit(types, i);
+			if (rc == 0)
+				continue;
+
+			/* Collect entries */
+			switch (type) {
+			case CEXPR_USER:
+				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+							policydb->p_user_val_to_name[i]);
+				break;
+			case CEXPR_ROLE:
+				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+							policydb->p_role_val_to_name[i]);
+				break;
+			case CEXPR_TYPE:
+				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+							policydb->p_type_val_to_name[i]);
+				break;
+			}
+			cat_expr_buf(expr_list[expr_counter], tmp_buf);
+		}
+	}
+	if (counter > 1)
+		cat_expr_buf(expr_list[expr_counter], " }");
+	if (failed)
+		cat_expr_buf(expr_list[expr_counter], " -Fail-) ");
+	else
+		cat_expr_buf(expr_list[expr_counter], ") ");
+
+	return;
+}
+
+static void msgcat(const char *src, const char *tgt, const char *op, int failed)
+{
+	char tmp_buf[128];
+	if (failed)
+		snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ",
+				src, op, tgt);
+	else
+		snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s) ",
+				src, op, tgt);
+	cat_expr_buf(expr_list[expr_counter], tmp_buf);
+}
+
+/* Returns a buffer with class, statement type and permissions */
+static char *get_class_info(sepol_security_class_t tclass,
+							constraint_node_t *constraint,
+							context_struct_t *xcontext)
+{
+	constraint_expr_t *e;
+	int mls, state_num;
+
+	/* Find if MLS statement or not */
+	mls = 0;
+	for (e = constraint->expr; e; e = e->next) {
+		if (e->attr >= CEXPR_L1L2) {
+			mls = 1;
+			break;
+		}
+	}
+
+	/* Determine statement type */
+	const char *statements[] = {
+		"constrain ",			/* 0 */
+		"mlsconstrain ",		/* 1 */
+		"validatetrans ",		/* 2 */
+		"mlsvalidatetrans ",	/* 3 */
+		0 };
+
+	if (xcontext == NULL)
+		state_num = mls + 0;
+	else
+		state_num = mls + 2;
+
+	int class_buf_len = 0;
+	int new_class_buf_len;
+	int len, buf_used;
+	char *class_buf = NULL, *p;
+	char *new_class_buf = NULL;
+
+	while (1) {
+		new_class_buf_len = class_buf_len + EXPR_BUF_SIZE;
+		new_class_buf = realloc(class_buf, new_class_buf_len);
+			if (!new_class_buf)
+				return NULL;
+		class_buf_len = new_class_buf_len;
+		class_buf = new_class_buf;
+		buf_used = 0;
+		p = class_buf;
+
+		/* Add statement type */
+		len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]);
+		if (len < 0 || len >= class_buf_len - buf_used)
+			continue;
+
+		/* Add class entry */
+		p += len;
+		buf_used += len;
+		len = snprintf(p, class_buf_len - buf_used, "%s ",
+				policydb->p_class_val_to_name[tclass - 1]);
+		if (len < 0 || len >= class_buf_len - buf_used)
+			continue;
+
+		/* Add permission entries (validatetrans does not have perms) */
+		p += len;
+		buf_used += len;
+		if (state_num < 2) {
+			len = snprintf(p, class_buf_len - buf_used, "{%s } (",
+			sepol_av_to_string(policydb, tclass,
+				constraint->permissions));
+		} else {
+			len = snprintf(p, class_buf_len - buf_used, "(");
+		}
+		if (len < 0 || len >= class_buf_len - buf_used)
+			continue;
+		break;
+	}
+	return class_buf;
+}
+
+/*
+ * Modified version of constraint_expr_eval that will process each
+ * constraint as before but adds the information to text buffers that
+ * will hold various components. The expression will be in RPN format,
+ * therefore there is a stack based RPN to infix converter to produce
+ * the final readable constraint.
+ *
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast...  It is used by the validatetrans rules
+ * only.  For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the
+ * context of the process performing the transition.  All other callers
+ * of constraint_expr_eval_reason should pass in NULL for xcontext.
+ *
+ * This function will also build a buffer as the constraint is processed
+ * for analysis. If this option is not required, then:
+ *      'tclass' should be '0' and r_buf MUST be NULL.
+ */
+static int constraint_expr_eval_reason(context_struct_t *scontext,
+				context_struct_t *tcontext,
+				context_struct_t *xcontext,
+				sepol_security_class_t tclass,
+				constraint_node_t *constraint,
+				char **r_buf,
+				unsigned int flags)
+{
+	uint32_t val1, val2;
+	context_struct_t *c;
+	role_datum_t *r1, *r2;
+	mls_level_t *l1, *l2;
+	constraint_expr_t *e;
+	int s[CEXPR_MAXDEPTH];
+	int sp = -1;
+	char tmp_buf[128];
+
+/*
+ * Define the s_t_x_num values that make up r1, t2 etc. in text strings
+ * Set 1 = source, 2 = target, 3 = xcontext for validatetrans
+ */
+#define SOURCE  1
+#define TARGET  2
+#define XTARGET 3
+
+	int s_t_x_num = SOURCE;
+
+	/* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */
+	int u_r_t = 0;
+
+	char *src = NULL;
+	char *tgt = NULL;
+	int rc = 0, x;
+	char *class_buf = NULL;
+
+	/*
+	 * The array of expression answer buffer pointers and counter.
+	 */
+	char **answer_list = NULL;
+	int answer_counter = 0;
+
+	class_buf = get_class_info(tclass, constraint, xcontext);
+	if (!class_buf) {
+		ERR(NULL, "failed to allocate class buffer");
+		return -ENOMEM;
+	}
+
+	/* Original function but with buffer support */
+	int expr_list_len = 0;
+	expr_counter = 0;
+	expr_list = NULL;
+	for (e = constraint->expr; e; e = e->next) {
+		/* Allocate a stack to hold expression buffer entries */
+		if (expr_counter >= expr_list_len) {
+			char **new_expr_list = expr_list;
+			int new_expr_list_len;
+
+			if (expr_list_len == 0)
+				new_expr_list_len = STACK_LEN;
+			else
+				new_expr_list_len = expr_list_len * 2;
+
+			new_expr_list = realloc(expr_list,
+					new_expr_list_len * sizeof(*expr_list));
+			if (!new_expr_list) {
+				ERR(NULL, "failed to allocate expr buffer stack");
+				rc = -ENOMEM;
+				goto out;
+			}
+			expr_list_len = new_expr_list_len;
+			expr_list = new_expr_list;
+		}
+
+		/*
+		 * malloc a buffer to store each expression text component. If
+		 * buffer is too small cat_expr_buf() will realloc extra space.
+		 */
+		expr_buf_len = EXPR_BUF_SIZE;
+		expr_list[expr_counter] = malloc(expr_buf_len);
+		if (!expr_list[expr_counter]) {
+			ERR(NULL, "failed to allocate expr buffer");
+			rc = -ENOMEM;
+			goto out;
+		}
+		expr_buf_used = 0;
+
+		/* Now process each expression of the constraint */
+		switch (e->expr_type) {
+		case CEXPR_NOT:
+			BUG_ON(sp < 0);
+			s[sp] = !s[sp];
+			cat_expr_buf(expr_list[expr_counter], "not");
+			break;
+		case CEXPR_AND:
+			BUG_ON(sp < 1);
+			sp--;
+			s[sp] &= s[sp + 1];
+			cat_expr_buf(expr_list[expr_counter], "and");
+			break;
+		case CEXPR_OR:
+			BUG_ON(sp < 1);
+			sp--;
+			s[sp] |= s[sp + 1];
+			cat_expr_buf(expr_list[expr_counter], "or");
+			break;
+		case CEXPR_ATTR:
+			if (sp == (CEXPR_MAXDEPTH - 1))
+				goto out;
+
+			switch (e->attr) {
+			case CEXPR_USER:
+				val1 = scontext->user;
+				val2 = tcontext->user;
+				free(src); src = strdup("u1");
+				free(tgt); tgt = strdup("u2");
+				break;
+			case CEXPR_TYPE:
+				val1 = scontext->type;
+				val2 = tcontext->type;
+				free(src); src = strdup("t1");
+				free(tgt); tgt = strdup("t2");
+				break;
+			case CEXPR_ROLE:
+				val1 = scontext->role;
+				val2 = tcontext->role;
+				r1 = policydb->role_val_to_struct[val1 - 1];
+				r2 = policydb->role_val_to_struct[val2 - 1];
+				free(src); src = strdup("r1");
+				free(tgt); tgt = strdup("r2");
+
+				switch (e->op) {
+				case CEXPR_DOM:
+					s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
+					msgcat(src, tgt, "dom", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_DOMBY:
+					s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
+					msgcat(src, tgt, "domby", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_INCOMP:
+					s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1)
+						 && !ebitmap_get_bit(&r2->dominates, val1 - 1));
+					msgcat(src, tgt, "incomp", s[sp] == 0);
+					expr_counter++;
+					continue;
+				default:
+					break;
+				}
+				break;
+			case CEXPR_L1L2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[0]);
+				free(src); src = strdup("l1");
+				free(tgt); tgt = strdup("l2");
+				goto mls_ops;
+			case CEXPR_L1H2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				free(src); src = strdup("l1");
+				free(tgt); tgt = strdup("h2");
+				goto mls_ops;
+			case CEXPR_H1L2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[0]);
+				free(src); src = strdup("h1");
+				free(tgt); tgt = strdup("l2");
+				goto mls_ops;
+			case CEXPR_H1H2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[1]);
+				free(src); src = strdup("h1");
+				free(tgt); tgt = strdup("h2");
+				goto mls_ops;
+			case CEXPR_L1H1:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(scontext->range.level[1]);
+				free(src); src = strdup("l1");
+				free(tgt); tgt = strdup("h1");
+				goto mls_ops;
+			case CEXPR_L2H2:
+				l1 = &(tcontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				free(src); src = strdup("l2");
+				free(tgt); tgt = strdup("h2");
+mls_ops:
+				switch (e->op) {
+				case CEXPR_EQ:
+					s[++sp] = mls_level_eq(l1, l2);
+					msgcat(src, tgt, "eq", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_NEQ:
+					s[++sp] = !mls_level_eq(l1, l2);
+					msgcat(src, tgt, "!=", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_DOM:
+					s[++sp] = mls_level_dom(l1, l2);
+					msgcat(src, tgt, "dom", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_DOMBY:
+					s[++sp] = mls_level_dom(l2, l1);
+					msgcat(src, tgt, "domby", s[sp] == 0);
+					expr_counter++;
+					continue;
+				case CEXPR_INCOMP:
+					s[++sp] = mls_level_incomp(l2, l1);
+					msgcat(src, tgt, "incomp", s[sp] == 0);
+					expr_counter++;
+					continue;
+				default:
+					BUG();
+					goto out;
+				}
+				break;
+			default:
+				BUG();
+				goto out;
+			}
+
+			switch (e->op) {
+			case CEXPR_EQ:
+				s[++sp] = (val1 == val2);
+				msgcat(src, tgt, "==", s[sp] == 0);
+				break;
+			case CEXPR_NEQ:
+				s[++sp] = (val1 != val2);
+				msgcat(src, tgt, "!=", s[sp] == 0);
+				break;
+			default:
+				BUG();
+				goto out;
+			}
+			break;
+		case CEXPR_NAMES:
+			if (sp == (CEXPR_MAXDEPTH - 1))
+				goto out;
+			s_t_x_num = SOURCE;
+			c = scontext;
+			if (e->attr & CEXPR_TARGET) {
+				s_t_x_num = TARGET;
+				c = tcontext;
+			} else if (e->attr & CEXPR_XTARGET) {
+				s_t_x_num = XTARGET;
+				c = xcontext;
+			}
+			if (!c) {
+				BUG();
+				goto out;
+			}
+			if (e->attr & CEXPR_USER) {
+				u_r_t = CEXPR_USER;
+				val1 = c->user;
+				snprintf(tmp_buf, sizeof(tmp_buf), "u%d ", s_t_x_num);
+				free(src); src = strdup(tmp_buf);
+			} else if (e->attr & CEXPR_ROLE) {
+				u_r_t = CEXPR_ROLE;
+				val1 = c->role;
+				snprintf(tmp_buf, sizeof(tmp_buf), "r%d ", s_t_x_num);
+				free(src); src = strdup(tmp_buf);
+			} else if (e->attr & CEXPR_TYPE) {
+				u_r_t = CEXPR_TYPE;
+				val1 = c->type;
+				snprintf(tmp_buf, sizeof(tmp_buf), "t%d ", s_t_x_num);
+				free(src); src = strdup(tmp_buf);
+			} else {
+				BUG();
+				goto out;
+			}
+
+			switch (e->op) {
+			case CEXPR_EQ:
+				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+				get_name_list(e, u_r_t, src, "==", s[sp] == 0);
+				break;
+
+			case CEXPR_NEQ:
+				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+				get_name_list(e, u_r_t, src, "!=", s[sp] == 0);
+				break;
+			default:
+				BUG();
+				goto out;
+			}
+			break;
+		default:
+			BUG();
+			goto out;
+		}
+		expr_counter++;
+	}
+
+	/*
+	 * At this point each expression of the constraint is in
+	 * expr_list[n+1] and in RPN format. Now convert to 'infix'
+	 */
+
+	/*
+	 * Save expr count but zero expr_counter to detect if
+	 * 'BUG(); goto out;' was called as we need to release any used
+	 * expr_list malloc's. Normally they are released by the RPN to
+	 * infix code.
+	 */
+	int expr_count = expr_counter;
+	expr_counter = 0;
+
+	/*
+	 * Generate the same number of answer buffer entries as expression
+	 * buffers (as there will never be more).
+	 */
+	answer_list = malloc(expr_count * sizeof(*answer_list));
+	if (!answer_list) {
+		ERR(NULL, "failed to allocate answer stack");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* The pop operands */
+	char *a;
+	char *b;
+	int a_len, b_len;
+
+	/* Convert constraint from RPN to infix notation. */
+	for (x = 0; x != expr_count; x++) {
+		if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x],
+					"or", 2) == 0) {
+			b = pop();
+			b_len = strlen(b);
+			a = pop();
+			a_len = strlen(a);
+
+			/* get a buffer to hold the answer */
+			answer_list[answer_counter] = malloc(a_len + b_len + 8);
+			if (!answer_list[answer_counter]) {
+				ERR(NULL, "failed to allocate answer buffer");
+				rc = -ENOMEM;
+				goto out;
+			}
+			memset(answer_list[answer_counter], '\0', a_len + b_len + 8);
+
+			sprintf(answer_list[answer_counter], "%s %s %s", a,
+					expr_list[x], b);
+			push(answer_list[answer_counter++]);
+			free(a);
+			free(b);
+			free(expr_list[x]);
+		} else if (strncmp(expr_list[x], "not", 3) == 0) {
+			b = pop();
+			b_len = strlen(b);
+
+			answer_list[answer_counter] = malloc(b_len + 8);
+			if (!answer_list[answer_counter]) {
+				ERR(NULL, "failed to allocate answer buffer");
+				rc = -ENOMEM;
+				goto out;
+			}
+			memset(answer_list[answer_counter], '\0', b_len + 8);
+
+			if (strncmp(b, "not", 3) == 0)
+				sprintf(answer_list[answer_counter], "%s (%s)",
+						expr_list[x], b);
+			else
+				sprintf(answer_list[answer_counter], "%s%s",
+						expr_list[x], b);
+			push(answer_list[answer_counter++]);
+			free(b);
+			free(expr_list[x]);
+		} else {
+			push(expr_list[x]);
+		}
+	}
+	/* Get the final answer from tos and build constraint text */
+	a = pop();
+
+	/* validatetrans / constraint calculation:
+				rc = 0 is denied, rc = 1 is granted */
+	sprintf(tmp_buf, "%s %s\n",
+			xcontext ? "Validatetrans" : "Constraint",
+			s[0] ? "GRANTED" : "DENIED");
+
+	int len, new_buf_len;
+	char *p, **new_buf = r_buf;
+	/*
+	 * These contain the constraint components that are added to the
+	 * callers reason buffer.
+	 */
+	const char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 };
+
+	/*
+	 * This will add the constraints to the callers reason buffer (who is
+	 * responsible for freeing the memory). It will handle any realloc's
+	 * should the buffer be too short.
+	 * The reason_buf_used and reason_buf_len counters are defined
+	 * globally as multiple constraints can be in the buffer.
+	 */
+
+	if (r_buf && ((s[0] == 0) || ((s[0] == 1 &&
+				(flags & SHOW_GRANTED) == SHOW_GRANTED)))) {
+		for (x = 0; buffers[x] != NULL; x++) {
+			while (1) {
+				p = *r_buf + reason_buf_used;
+				len = snprintf(p, reason_buf_len - reason_buf_used,
+						"%s", buffers[x]);
+				if (len < 0 || len >= reason_buf_len - reason_buf_used) {
+					new_buf_len = reason_buf_len + REASON_BUF_SIZE;
+					*new_buf = realloc(*r_buf, new_buf_len);
+					if (!new_buf) {
+						ERR(NULL, "failed to realloc reason buffer");
+						goto out1;
+					}
+					**r_buf = **new_buf;
+					reason_buf_len = new_buf_len;
+					continue;
+				} else {
+					reason_buf_used += len;
+					break;
+				}
+			}
+		}
+	}
+
+out1:
+	rc = s[0];
+	free(a);
+
+out:
+	free(class_buf);
+	free(src);
+	free(tgt);
+
+	if (expr_counter) {
+		for (x = 0; expr_list[x] != NULL; x++)
+			free(expr_list[x]);
+	}
+	free(answer_list);
+	free(expr_list);
+	return rc;
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(context_struct_t * scontext,
+				     context_struct_t * tcontext,
+				     sepol_security_class_t tclass,
+				     sepol_access_vector_t requested,
+				     struct sepol_av_decision *avd,
+				     unsigned int *reason,
+				     char **r_buf,
+					 unsigned int flags)
+{
+	constraint_node_t *constraint;
+	struct role_allow *ra;
+	avtab_key_t avkey;
+	class_datum_t *tclass_datum;
+	avtab_ptr_t node;
+	ebitmap_t *sattr, *tattr;
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+
+	if (!tclass || tclass > policydb->p_classes.nprim) {
+		ERR(NULL, "unrecognized class %d", tclass);
+		return -EINVAL;
+	}
+	tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+	/* 
+	 * Initialize the access vectors to the default values.
+	 */
+	avd->allowed = 0;
+	avd->decided = 0xffffffff;
+	avd->auditallow = 0;
+	avd->auditdeny = 0xffffffff;
+	avd->seqno = latest_granting;
+	*reason = 0;
+
+	/*
+	 * If a specific type enforcement rule was defined for
+	 * this permission check, then use it.
+	 */
+	avkey.target_class = tclass;
+	avkey.specified = AVTAB_AV;
+	sattr = &policydb->type_attr_map[scontext->type - 1];
+	tattr = &policydb->type_attr_map[tcontext->type - 1];
+	ebitmap_for_each_bit(sattr, snode, i) {
+		if (!ebitmap_node_get_bit(snode, i))
+			continue;
+		ebitmap_for_each_bit(tattr, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			avkey.source_type = i + 1;
+			avkey.target_type = j + 1;
+			for (node =
+			     avtab_search_node(&policydb->te_avtab, &avkey);
+			     node != NULL;
+			     node =
+			     avtab_search_node_next(node, avkey.specified)) {
+				if (node->key.specified == AVTAB_ALLOWED)
+					avd->allowed |= node->datum.data;
+				else if (node->key.specified ==
+					 AVTAB_AUDITALLOW)
+					avd->auditallow |= node->datum.data;
+				else if (node->key.specified == AVTAB_AUDITDENY)
+					avd->auditdeny &= node->datum.data;
+			}
+
+			/* Check conditional av table for additional permissions */
+			cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
+
+		}
+	}
+
+	if (requested & ~avd->allowed) {
+		*reason |= SEPOL_COMPUTEAV_TE;
+		requested &= avd->allowed;
+	}
+
+	/* 
+	 * Remove any permissions prohibited by a constraint (this includes
+	 * the MLS policy).
+	 */
+	constraint = tclass_datum->constraints;
+	while (constraint) {
+		if ((constraint->permissions & (avd->allowed)) &&
+		    !constraint_expr_eval_reason(scontext, tcontext, NULL,
+					  tclass, constraint, r_buf, flags)) {
+			avd->allowed =
+			    (avd->allowed) & ~(constraint->permissions);
+		}
+		constraint = constraint->next;
+	}
+
+	if (requested & ~avd->allowed) {
+		*reason |= SEPOL_COMPUTEAV_CONS;
+		requested &= avd->allowed;
+	}
+
+	/* 
+	 * If checking process transition permission and the
+	 * role is changing, then check the (current_role, new_role) 
+	 * pair.
+	 */
+	if (tclass == SECCLASS_PROCESS &&
+	    (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
+	    scontext->role != tcontext->role) {
+		for (ra = policydb->role_allow; ra; ra = ra->next) {
+			if (scontext->role == ra->role &&
+			    tcontext->role == ra->new_role)
+				break;
+		}
+		if (!ra)
+			avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
+							  PROCESS__DYNTRANSITION);
+	}
+
+	if (requested & ~avd->allowed) {
+		*reason |= SEPOL_COMPUTEAV_RBAC;
+		requested &= avd->allowed;
+	}
+
+	return 0;
+}
+
+int hidden sepol_validate_transition(sepol_security_id_t oldsid,
+				     sepol_security_id_t newsid,
+				     sepol_security_id_t tasksid,
+				     sepol_security_class_t tclass)
+{
+	context_struct_t *ocontext;
+	context_struct_t *ncontext;
+	context_struct_t *tcontext;
+	class_datum_t *tclass_datum;
+	constraint_node_t *constraint;
+
+	if (!tclass || tclass > policydb->p_classes.nprim) {
+		ERR(NULL, "unrecognized class %d", tclass);
+		return -EINVAL;
+	}
+	tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+	ocontext = sepol_sidtab_search(sidtab, oldsid);
+	if (!ocontext) {
+		ERR(NULL, "unrecognized SID %d", oldsid);
+		return -EINVAL;
+	}
+
+	ncontext = sepol_sidtab_search(sidtab, newsid);
+	if (!ncontext) {
+		ERR(NULL, "unrecognized SID %d", newsid);
+		return -EINVAL;
+	}
+
+	tcontext = sepol_sidtab_search(sidtab, tasksid);
+	if (!tcontext) {
+		ERR(NULL, "unrecognized SID %d", tasksid);
+		return -EINVAL;
+	}
+
+	constraint = tclass_datum->validatetrans;
+	while (constraint) {
+		if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
+					  0, constraint, NULL, 0)) {
+			return -EPERM;
+		}
+		constraint = constraint->next;
+	}
+
+	return 0;
+}
+
+/*
+ * sepol_validate_transition_reason_buffer - the reason buffer is realloc'd
+ * in the constraint_expr_eval_reason() function.
+ */
+int hidden sepol_validate_transition_reason_buffer(sepol_security_id_t oldsid,
+				     sepol_security_id_t newsid,
+				     sepol_security_id_t tasksid,
+				     sepol_security_class_t tclass,
+				     char **reason_buf,
+				     unsigned int flags)
+{
+	context_struct_t *ocontext;
+	context_struct_t *ncontext;
+	context_struct_t *tcontext;
+	class_datum_t *tclass_datum;
+	constraint_node_t *constraint;
+
+	if (!tclass || tclass > policydb->p_classes.nprim) {
+		ERR(NULL, "unrecognized class %d", tclass);
+		return -EINVAL;
+	}
+	tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+	ocontext = sepol_sidtab_search(sidtab, oldsid);
+	if (!ocontext) {
+		ERR(NULL, "unrecognized SID %d", oldsid);
+		return -EINVAL;
+	}
+
+	ncontext = sepol_sidtab_search(sidtab, newsid);
+	if (!ncontext) {
+		ERR(NULL, "unrecognized SID %d", newsid);
+		return -EINVAL;
+	}
+
+	tcontext = sepol_sidtab_search(sidtab, tasksid);
+	if (!tcontext) {
+		ERR(NULL, "unrecognized SID %d", tasksid);
+		return -EINVAL;
+	}
+
+	/*
+	 * Set the buffer to NULL as mls/validatetrans may not be processed.
+	 * If a buffer is required, then the routines in
+	 * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE
+	 * chunks (as it gets called for each mls/validatetrans processed).
+	 * We just make sure these start from zero.
+	 */
+	*reason_buf = NULL;
+	reason_buf_used = 0;
+	reason_buf_len = 0;
+	constraint = tclass_datum->validatetrans;
+	while (constraint) {
+		if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
+				tclass, constraint, reason_buf, flags)) {
+			return -EPERM;
+		}
+		constraint = constraint->next;
+	}
+	return 0;
+}
+
+int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
+				   sepol_security_id_t tsid,
+				   sepol_security_class_t tclass,
+				   sepol_access_vector_t requested,
+				   struct sepol_av_decision *avd,
+				   unsigned int *reason)
+{
+	context_struct_t *scontext = 0, *tcontext = 0;
+	int rc = 0;
+
+	scontext = sepol_sidtab_search(sidtab, ssid);
+	if (!scontext) {
+		ERR(NULL, "unrecognized SID %d", ssid);
+		rc = -EINVAL;
+		goto out;
+	}
+	tcontext = sepol_sidtab_search(sidtab, tsid);
+	if (!tcontext) {
+		ERR(NULL, "unrecognized SID %d", tsid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = context_struct_compute_av(scontext, tcontext, tclass,
+					requested, avd, reason, NULL, 0);
+      out:
+	return rc;
+}
+
+/*
+ * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to
+ * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd
+ * in the constraint_expr_eval_reason() function.
+ */
+int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
+				   sepol_security_id_t tsid,
+				   sepol_security_class_t tclass,
+				   sepol_access_vector_t requested,
+				   struct sepol_av_decision *avd,
+				   unsigned int *reason,
+				   char **reason_buf,
+				   unsigned int flags)
+{
+	context_struct_t *scontext = 0, *tcontext = 0;
+	int rc = 0;
+
+	scontext = sepol_sidtab_search(sidtab, ssid);
+	if (!scontext) {
+		ERR(NULL, "unrecognized SID %d", ssid);
+		rc = -EINVAL;
+		goto out;
+	}
+	tcontext = sepol_sidtab_search(sidtab, tsid);
+	if (!tcontext) {
+		ERR(NULL, "unrecognized SID %d", tsid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Set the buffer to NULL as constraints may not be processed.
+	 * If a buffer is required, then the routines in
+	 * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE
+	 * chunks (as it gets called for each constraint processed).
+	 * We just make sure these start from zero.
+	 */
+	*reason_buf = NULL;
+	reason_buf_used = 0;
+	reason_buf_len = 0;
+
+	rc = context_struct_compute_av(scontext, tcontext, tclass,
+					   requested, avd, reason, reason_buf, flags);
+out:
+	return rc;
+}
+
+int hidden sepol_compute_av(sepol_security_id_t ssid,
+			    sepol_security_id_t tsid,
+			    sepol_security_class_t tclass,
+			    sepol_access_vector_t requested,
+			    struct sepol_av_decision *avd)
+{
+	unsigned int reason = 0;
+	return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
+				       &reason);
+}
+
+/*
+ * Return a class ID associated with the class string specified by
+ * class_name.
+ */
+int hidden sepol_string_to_security_class(const char *class_name,
+			sepol_security_class_t *tclass)
+{
+	char *class = NULL;
+	sepol_security_class_t id;
+
+	for (id = 1;; id++) {
+		class = policydb->p_class_val_to_name[id - 1];
+		if (class == NULL) {
+			ERR(NULL, "could not convert %s to class id", class_name);
+			return STATUS_ERR;
+		}
+		if ((strcmp(class, class_name)) == 0) {
+			*tclass = id;
+			return STATUS_SUCCESS;
+		}
+	}
+}
+
+/*
+ * Return access vector bit associated with the class ID and permission
+ * string.
+ */
+int hidden sepol_string_to_av_perm(sepol_security_class_t tclass,
+					const char *perm_name,
+					sepol_access_vector_t *av)
+{
+	class_datum_t *tclass_datum;
+	perm_datum_t *perm_datum;
+
+	if (!tclass || tclass > policydb->p_classes.nprim) {
+		ERR(NULL, "unrecognized class %d", tclass);
+		return -EINVAL;
+	}
+	tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+	/* Check for unique perms then the common ones (if any) */
+	perm_datum = (perm_datum_t *)
+			hashtab_search(tclass_datum->permissions.table,
+			(hashtab_key_t)perm_name);
+	if (perm_datum != NULL) {
+		*av = 0x1 << (perm_datum->s.value - 1);
+		return STATUS_SUCCESS;
+	}
+
+	if (tclass_datum->comdatum == NULL)
+		goto out;
+
+	perm_datum = (perm_datum_t *)
+			hashtab_search(tclass_datum->comdatum->permissions.table,
+			(hashtab_key_t)perm_name);
+
+	if (perm_datum != NULL) {
+		*av = 0x1 << (perm_datum->s.value - 1);
+		return STATUS_SUCCESS;
+	}
+out:
+	ERR(NULL, "could not convert %s to av bit", perm_name);
+	return STATUS_ERR;
+}
+
+/*
+ * Write the security context string representation of 
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size.  Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int hidden sepol_sid_to_context(sepol_security_id_t sid,
+				sepol_security_context_t * scontext,
+				size_t * scontext_len)
+{
+	context_struct_t *context;
+	int rc = 0;
+
+	context = sepol_sidtab_search(sidtab, sid);
+	if (!context) {
+		ERR(NULL, "unrecognized SID %d", sid);
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
+      out:
+	return rc;
+
+}
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
+				size_t scontext_len, sepol_security_id_t * sid)
+{
+
+	context_struct_t *context = NULL;
+
+	/* First, create the context */
+	if (context_from_string(NULL, policydb, &context,
+				scontext, scontext_len) < 0)
+		goto err;
+
+	/* Obtain the new sid */
+	if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
+		goto err;
+
+	context_destroy(context);
+	free(context);
+	return STATUS_SUCCESS;
+
+      err:
+	if (context) {
+		context_destroy(context);
+		free(context);
+	}
+	ERR(NULL, "could not convert %s to sid", scontext);
+	return STATUS_ERR;
+}
+
+static inline int compute_sid_handle_invalid_context(context_struct_t *
+						     scontext,
+						     context_struct_t *
+						     tcontext,
+						     sepol_security_class_t
+						     tclass,
+						     context_struct_t *
+						     newcontext)
+{
+	if (selinux_enforcing) {
+		return -EACCES;
+	} else {
+		sepol_security_context_t s, t, n;
+		size_t slen, tlen, nlen;
+
+		context_to_string(NULL, policydb, scontext, &s, &slen);
+		context_to_string(NULL, policydb, tcontext, &t, &tlen);
+		context_to_string(NULL, policydb, newcontext, &n, &nlen);
+		ERR(NULL, "invalid context %s for "
+		    "scontext=%s tcontext=%s tclass=%s",
+		    n, s, t, policydb->p_class_val_to_name[tclass - 1]);
+		free(s);
+		free(t);
+		free(n);
+		return 0;
+	}
+}
+
+static int sepol_compute_sid(sepol_security_id_t ssid,
+			     sepol_security_id_t tsid,
+			     sepol_security_class_t tclass,
+			     uint32_t specified, sepol_security_id_t * out_sid)
+{
+	context_struct_t *scontext = 0, *tcontext = 0, newcontext;
+	struct role_trans *roletr = 0;
+	avtab_key_t avkey;
+	avtab_datum_t *avdatum;
+	avtab_ptr_t node;
+	int rc = 0;
+
+	scontext = sepol_sidtab_search(sidtab, ssid);
+	if (!scontext) {
+		ERR(NULL, "unrecognized SID %d", ssid);
+		rc = -EINVAL;
+		goto out;
+	}
+	tcontext = sepol_sidtab_search(sidtab, tsid);
+	if (!tcontext) {
+		ERR(NULL, "unrecognized SID %d", tsid);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	context_init(&newcontext);
+
+	/* Set the user identity. */
+	switch (specified) {
+	case AVTAB_TRANSITION:
+	case AVTAB_CHANGE:
+		/* Use the process user identity. */
+		newcontext.user = scontext->user;
+		break;
+	case AVTAB_MEMBER:
+		/* Use the related object owner. */
+		newcontext.user = tcontext->user;
+		break;
+	}
+
+	/* Set the role and type to default values. */
+	switch (tclass) {
+	case SECCLASS_PROCESS:
+		/* Use the current role and type of process. */
+		newcontext.role = scontext->role;
+		newcontext.type = scontext->type;
+		break;
+	default:
+		/* Use the well-defined object role. */
+		newcontext.role = OBJECT_R_VAL;
+		/* Use the type of the related object. */
+		newcontext.type = tcontext->type;
+	}
+
+	/* Look for a type transition/member/change rule. */
+	avkey.source_type = scontext->type;
+	avkey.target_type = tcontext->type;
+	avkey.target_class = tclass;
+	avkey.specified = specified;
+	avdatum = avtab_search(&policydb->te_avtab, &avkey);
+
+	/* If no permanent rule, also check for enabled conditional rules */
+	if (!avdatum) {
+		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
+		for (; node != NULL;
+		     node = avtab_search_node_next(node, specified)) {
+			if (node->key.specified & AVTAB_ENABLED) {
+				avdatum = &node->datum;
+				break;
+			}
+		}
+	}
+
+	if (avdatum) {
+		/* Use the type from the type transition/member/change rule. */
+		newcontext.type = avdatum->data;
+	}
+
+	/* Check for class-specific changes. */
+	switch (tclass) {
+	case SECCLASS_PROCESS:
+		if (specified & AVTAB_TRANSITION) {
+			/* Look for a role transition rule. */
+			for (roletr = policydb->role_tr; roletr;
+			     roletr = roletr->next) {
+				if (roletr->role == scontext->role &&
+				    roletr->type == tcontext->type) {
+					/* Use the role transition rule. */
+					newcontext.role = roletr->new_role;
+					break;
+				}
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* Set the MLS attributes.
+	   This is done last because it may allocate memory. */
+	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
+			     &newcontext);
+	if (rc)
+		goto out;
+
+	/* Check the validity of the context. */
+	if (!policydb_context_isvalid(policydb, &newcontext)) {
+		rc = compute_sid_handle_invalid_context(scontext,
+							tcontext,
+							tclass, &newcontext);
+		if (rc)
+			goto out;
+	}
+	/* Obtain the sid for the context. */
+	rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
+      out:
+	context_destroy(&newcontext);
+	return rc;
+}
+
+/*
+ * Compute a SID to use for labeling a new object in the 
+ * class `tclass' based on a SID pair.  
+ */
+int hidden sepol_transition_sid(sepol_security_id_t ssid,
+				sepol_security_id_t tsid,
+				sepol_security_class_t tclass,
+				sepol_security_id_t * out_sid)
+{
+	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/*
+ * Compute a SID to use when selecting a member of a 
+ * polyinstantiated object of class `tclass' based on 
+ * a SID pair.
+ */
+int hidden sepol_member_sid(sepol_security_id_t ssid,
+			    sepol_security_id_t tsid,
+			    sepol_security_class_t tclass,
+			    sepol_security_id_t * out_sid)
+{
+	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/*
+ * Compute a SID to use for relabeling an object in the 
+ * class `tclass' based on a SID pair.  
+ */
+int hidden sepol_change_sid(sepol_security_id_t ssid,
+			    sepol_security_id_t tsid,
+			    sepol_security_class_t tclass,
+			    sepol_security_id_t * out_sid)
+{
+	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+	hashtab_t h;
+	perm_datum_t *perdatum, *perdatum2;
+
+	h = (hashtab_t) p;
+	perdatum = (perm_datum_t *) datum;
+
+	perdatum2 = (perm_datum_t *) hashtab_search(h, key);
+	if (!perdatum2) {
+		ERR(NULL, "permission %s disappeared", key);
+		return -1;
+	}
+	if (perdatum->s.value != perdatum2->s.value) {
+		ERR(NULL, "the value of permissions %s changed", key);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same 
+ * attributes in the new policy.
+ */
+static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+	policydb_t *newp;
+	class_datum_t *cladatum, *cladatum2;
+
+	newp = (policydb_t *) p;
+	cladatum = (class_datum_t *) datum;
+
+	cladatum2 =
+	    (class_datum_t *) hashtab_search(newp->p_classes.table, key);
+	if (!cladatum2) {
+		ERR(NULL, "class %s disappeared", key);
+		return -1;
+	}
+	if (cladatum->s.value != cladatum2->s.value) {
+		ERR(NULL, "the value of class %s changed", key);
+		return -1;
+	}
+	if ((cladatum->comdatum && !cladatum2->comdatum) ||
+	    (!cladatum->comdatum && cladatum2->comdatum)) {
+		ERR(NULL, "the inherits clause for the access "
+		    "vector definition for class %s changed", key);
+		return -1;
+	}
+	if (cladatum->comdatum) {
+		if (hashtab_map
+		    (cladatum->comdatum->permissions.table, validate_perm,
+		     cladatum2->comdatum->permissions.table)) {
+			ERR(NULL,
+			    " in the access vector definition "
+			    "for class %s\n", key);
+			return -1;
+		}
+	}
+	if (hashtab_map(cladatum->permissions.table, validate_perm,
+			cladatum2->permissions.table)) {
+		ERR(NULL, " in access vector definition for class %s", key);
+		return -1;
+	}
+	return 0;
+}
+
+/* Clone the SID into the new SID table. */
+static int clone_sid(sepol_security_id_t sid,
+		     context_struct_t * context, void *arg)
+{
+	sidtab_t *s = arg;
+
+	return sepol_sidtab_insert(s, sid, context);
+}
+
+static inline int convert_context_handle_invalid_context(context_struct_t *
+							 context)
+{
+	if (selinux_enforcing) {
+		return -EINVAL;
+	} else {
+		sepol_security_context_t s;
+		size_t len;
+
+		context_to_string(NULL, policydb, context, &s, &len);
+		ERR(NULL, "context %s is invalid", s);
+		free(s);
+		return 0;
+	}
+}
+
+typedef struct {
+	policydb_t *oldp;
+	policydb_t *newp;
+} convert_context_args_t;
+
+/*
+ * Convert the values in the security context
+ * structure `c' from the values specified
+ * in the policy `p->oldp' to the values specified
+ * in the policy `p->newp'.  Verify that the
+ * context is valid under the new policy.
+ */
+static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
+			   context_struct_t * c, void *p)
+{
+	convert_context_args_t *args;
+	context_struct_t oldc;
+	role_datum_t *role;
+	type_datum_t *typdatum;
+	user_datum_t *usrdatum;
+	sepol_security_context_t s;
+	size_t len;
+	int rc = -EINVAL;
+
+	args = (convert_context_args_t *) p;
+
+	if (context_cpy(&oldc, c))
+		return -ENOMEM;
+
+	/* Convert the user. */
+	usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
+						   args->oldp->
+						   p_user_val_to_name[c->user -
+								      1]);
+
+	if (!usrdatum) {
+		goto bad;
+	}
+	c->user = usrdatum->s.value;
+
+	/* Convert the role. */
+	role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
+					       args->oldp->
+					       p_role_val_to_name[c->role - 1]);
+	if (!role) {
+		goto bad;
+	}
+	c->role = role->s.value;
+
+	/* Convert the type. */
+	typdatum = (type_datum_t *)
+	    hashtab_search(args->newp->p_types.table,
+			   args->oldp->p_type_val_to_name[c->type - 1]);
+	if (!typdatum) {
+		goto bad;
+	}
+	c->type = typdatum->s.value;
+
+	rc = mls_convert_context(args->oldp, args->newp, c);
+	if (rc)
+		goto bad;
+
+	/* Check the validity of the new context. */
+	if (!policydb_context_isvalid(args->newp, c)) {
+		rc = convert_context_handle_invalid_context(&oldc);
+		if (rc)
+			goto bad;
+	}
+
+	context_destroy(&oldc);
+	return 0;
+
+      bad:
+	context_to_string(NULL, policydb, &oldc, &s, &len);
+	context_destroy(&oldc);
+	ERR(NULL, "invalidating context %s", s);
+	free(s);
+	return rc;
+}
+
+/* Reading from a policy "file". */
+int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
+{
+	size_t nread;
+
+	switch (fp->type) {
+	case PF_USE_STDIO:
+		nread = fread(buf, bytes, 1, fp->fp);
+
+		if (nread != 1)
+			return -1;
+		break;
+	case PF_USE_MEMORY:
+		if (bytes > fp->len)
+			return -1;
+		memcpy(buf, fp->data, bytes);
+		fp->data += bytes;
+		fp->len -= bytes;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+size_t hidden put_entry(const void *ptr, size_t size, size_t n,
+			struct policy_file *fp)
+{
+	size_t bytes = size * n;
+
+	switch (fp->type) {
+	case PF_USE_STDIO:
+		return fwrite(ptr, size, n, fp->fp);
+	case PF_USE_MEMORY:
+		if (bytes > fp->len) {
+			errno = ENOSPC;
+			return 0;
+		}
+
+		memcpy(fp->data, ptr, bytes);
+		fp->data += bytes;
+		fp->len -= bytes;
+		return n;
+	case PF_LEN:
+		fp->len += bytes;
+		return n;
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * Read a new set of configuration data from 
+ * a policy database binary representation file.
+ *
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same 
+ * attributes in the new policy.  
+ *
+ * Convert the context structures in the SID table to the
+ * new representation and verify that all entries
+ * in the SID table are valid under the new policy. 
+ *
+ * Change the active policy database to use the new 
+ * configuration data.  
+ *
+ * Reset the access vector cache.
+ */
+int hidden sepol_load_policy(void *data, size_t len)
+{
+	policydb_t oldpolicydb, newpolicydb;
+	sidtab_t oldsidtab, newsidtab;
+	convert_context_args_t args;
+	int rc = 0;
+	struct policy_file file, *fp;
+
+	policy_file_init(&file);
+	file.type = PF_USE_MEMORY;
+	file.data = data;
+	file.len = len;
+	fp = &file;
+
+	if (policydb_init(&newpolicydb))
+		return -ENOMEM;
+
+	if (policydb_read(&newpolicydb, fp, 1)) {
+		policydb_destroy(&mypolicydb);
+		return -EINVAL;
+	}
+
+	sepol_sidtab_init(&newsidtab);
+
+	/* Verify that the existing classes did not change. */
+	if (hashtab_map
+	    (policydb->p_classes.table, validate_class, &newpolicydb)) {
+		ERR(NULL, "the definition of an existing class changed");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Clone the SID table. */
+	sepol_sidtab_shutdown(sidtab);
+	if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* Convert the internal representations of contexts 
+	   in the new SID table and remove invalid SIDs. */
+	args.oldp = policydb;
+	args.newp = &newpolicydb;
+	sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+
+	/* Save the old policydb and SID table to free later. */
+	memcpy(&oldpolicydb, policydb, sizeof *policydb);
+	sepol_sidtab_set(&oldsidtab, sidtab);
+
+	/* Install the new policydb and SID table. */
+	memcpy(policydb, &newpolicydb, sizeof *policydb);
+	sepol_sidtab_set(sidtab, &newsidtab);
+
+	/* Free the old policydb and SID table. */
+	policydb_destroy(&oldpolicydb);
+	sepol_sidtab_destroy(&oldsidtab);
+
+	return 0;
+
+      err:
+	sepol_sidtab_destroy(&newsidtab);
+	policydb_destroy(&newpolicydb);
+	return rc;
+
+}
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'.  The `fs_sid' SID is returned for 
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+int hidden sepol_fs_sid(char *name,
+			sepol_security_id_t * fs_sid,
+			sepol_security_id_t * file_sid)
+{
+	int rc = 0;
+	ocontext_t *c;
+
+	c = policydb->ocontexts[OCON_FS];
+	while (c) {
+		if (strcmp(c->u.name, name) == 0)
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		if (!c->sid[0] || !c->sid[1]) {
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[0],
+							 &c->sid[0]);
+			if (rc)
+				goto out;
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[1],
+							 &c->sid[1]);
+			if (rc)
+				goto out;
+		}
+		*fs_sid = c->sid[0];
+		*file_sid = c->sid[1];
+	} else {
+		*fs_sid = SECINITSID_FS;
+		*file_sid = SECINITSID_FILE;
+	}
+
+      out:
+	return rc;
+}
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
+			  uint16_t type __attribute__ ((unused)),
+			  uint8_t protocol,
+			  uint16_t port, sepol_security_id_t * out_sid)
+{
+	ocontext_t *c;
+	int rc = 0;
+
+	c = policydb->ocontexts[OCON_PORT];
+	while (c) {
+		if (c->u.port.protocol == protocol &&
+		    c->u.port.low_port <= port && c->u.port.high_port >= port)
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		if (!c->sid[0]) {
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[0],
+							 &c->sid[0]);
+			if (rc)
+				goto out;
+		}
+		*out_sid = c->sid[0];
+	} else {
+		*out_sid = SECINITSID_PORT;
+	}
+
+      out:
+	return rc;
+}
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'.  The `if_sid' SID is returned for 
+ * the interface and the `msg_sid' SID is returned as 
+ * the default SID for messages received on the
+ * interface.
+ */
+int hidden sepol_netif_sid(char *name,
+			   sepol_security_id_t * if_sid,
+			   sepol_security_id_t * msg_sid)
+{
+	int rc = 0;
+	ocontext_t *c;
+
+	c = policydb->ocontexts[OCON_NETIF];
+	while (c) {
+		if (strcmp(name, c->u.name) == 0)
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		if (!c->sid[0] || !c->sid[1]) {
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[0],
+							 &c->sid[0]);
+			if (rc)
+				goto out;
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[1],
+							 &c->sid[1]);
+			if (rc)
+				goto out;
+		}
+		*if_sid = c->sid[0];
+		*msg_sid = c->sid[1];
+	} else {
+		*if_sid = SECINITSID_NETIF;
+		*msg_sid = SECINITSID_NETMSG;
+	}
+
+      out:
+	return rc;
+}
+
+static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
+			       uint32_t * mask)
+{
+	int i, fail = 0;
+
+	for (i = 0; i < 4; i++)
+		if (addr[i] != (input[i] & mask[i])) {
+			fail = 1;
+			break;
+		}
+
+	return !fail;
+}
+
+/*
+ * Return the SID of the node specified by the address
+ * `addrp' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+int hidden sepol_node_sid(uint16_t domain,
+			  void *addrp,
+			  size_t addrlen, sepol_security_id_t * out_sid)
+{
+	int rc = 0;
+	ocontext_t *c;
+
+	switch (domain) {
+	case AF_INET:{
+			uint32_t addr;
+
+			if (addrlen != sizeof(uint32_t)) {
+				rc = -EINVAL;
+				goto out;
+			}
+
+			addr = *((uint32_t *) addrp);
+
+			c = policydb->ocontexts[OCON_NODE];
+			while (c) {
+				if (c->u.node.addr == (addr & c->u.node.mask))
+					break;
+				c = c->next;
+			}
+			break;
+		}
+
+	case AF_INET6:
+		if (addrlen != sizeof(uint64_t) * 2) {
+			rc = -EINVAL;
+			goto out;
+		}
+
+		c = policydb->ocontexts[OCON_NODE6];
+		while (c) {
+			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
+						c->u.node6.mask))
+				break;
+			c = c->next;
+		}
+		break;
+
+	default:
+		*out_sid = SECINITSID_NODE;
+		goto out;
+	}
+
+	if (c) {
+		if (!c->sid[0]) {
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[0],
+							 &c->sid[0]);
+			if (rc)
+				goto out;
+		}
+		*out_sid = c->sid[0];
+	} else {
+		*out_sid = SECINITSID_NODE;
+	}
+
+      out:
+	return rc;
+}
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated 
+ * array containing the set of SIDs.  Set `*nel' to the
+ * number of elements in the array.
+ */
+#define SIDS_NEL 25
+
+int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
+			       char *username,
+			       sepol_security_id_t ** sids, uint32_t * nel)
+{
+	context_struct_t *fromcon, usercon;
+	sepol_security_id_t *mysids, *mysids2, sid;
+	uint32_t mynel = 0, maxnel = SIDS_NEL;
+	user_datum_t *user;
+	role_datum_t *role;
+	struct sepol_av_decision avd;
+	int rc = 0;
+	unsigned int i, j, reason;
+	ebitmap_node_t *rnode, *tnode;
+
+	fromcon = sepol_sidtab_search(sidtab, fromsid);
+	if (!fromcon) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	user = (user_datum_t *) hashtab_search(policydb->p_users.table,
+					       username);
+	if (!user) {
+		rc = -EINVAL;
+		goto out;
+	}
+	usercon.user = user->s.value;
+
+	mysids = malloc(maxnel * sizeof(sepol_security_id_t));
+	if (!mysids) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
+
+	ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
+		if (!ebitmap_node_get_bit(rnode, i))
+			continue;
+		role = policydb->role_val_to_struct[i];
+		usercon.role = i + 1;
+		ebitmap_for_each_bit(&role->types.types, tnode, j) {
+			if (!ebitmap_node_get_bit(tnode, j))
+				continue;
+			usercon.type = j + 1;
+			if (usercon.type == fromcon->type)
+				continue;
+
+			if (mls_setup_user_range
+			    (fromcon, user, &usercon, policydb->mls))
+				continue;
+
+			rc = context_struct_compute_av(fromcon, &usercon,
+						       SECCLASS_PROCESS,
+						       PROCESS__TRANSITION,
+						       &avd, &reason, NULL, 0);
+			if (rc || !(avd.allowed & PROCESS__TRANSITION))
+				continue;
+			rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
+							 &sid);
+			if (rc) {
+				free(mysids);
+				goto out;
+			}
+			if (mynel < maxnel) {
+				mysids[mynel++] = sid;
+			} else {
+				maxnel += SIDS_NEL;
+				mysids2 =
+				    malloc(maxnel *
+					   sizeof(sepol_security_id_t));
+
+				if (!mysids2) {
+					rc = -ENOMEM;
+					free(mysids);
+					goto out;
+				}
+				memset(mysids2, 0,
+				       maxnel * sizeof(sepol_security_id_t));
+				memcpy(mysids2, mysids,
+				       mynel * sizeof(sepol_security_id_t));
+				free(mysids);
+				mysids = mysids2;
+				mysids[mynel++] = sid;
+			}
+		}
+	}
+
+	*sids = mysids;
+	*nel = mynel;
+
+      out:
+	return rc;
+}
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+int hidden sepol_genfs_sid(const char *fstype,
+			   const char *path,
+			   sepol_security_class_t sclass,
+			   sepol_security_id_t * sid)
+{
+	size_t len;
+	genfs_t *genfs;
+	ocontext_t *c;
+	int rc = 0, cmp = 0;
+
+	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
+		cmp = strcmp(fstype, genfs->fstype);
+		if (cmp <= 0)
+			break;
+	}
+
+	if (!genfs || cmp) {
+		*sid = SECINITSID_UNLABELED;
+		rc = -ENOENT;
+		goto out;
+	}
+
+	for (c = genfs->head; c; c = c->next) {
+		len = strlen(c->u.name);
+		if ((!c->v.sclass || sclass == c->v.sclass) &&
+		    (strncmp(c->u.name, path, len) == 0))
+			break;
+	}
+
+	if (!c) {
+		*sid = SECINITSID_UNLABELED;
+		rc = -ENOENT;
+		goto out;
+	}
+
+	if (!c->sid[0]) {
+		rc = sepol_sidtab_context_to_sid(sidtab,
+						 &c->context[0], &c->sid[0]);
+		if (rc)
+			goto out;
+	}
+
+	*sid = c->sid[0];
+      out:
+	return rc;
+}
+
+int hidden sepol_fs_use(const char *fstype,
+			unsigned int *behavior, sepol_security_id_t * sid)
+{
+	int rc = 0;
+	ocontext_t *c;
+
+	c = policydb->ocontexts[OCON_FSUSE];
+	while (c) {
+		if (strcmp(fstype, c->u.name) == 0)
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		*behavior = c->v.behavior;
+		if (!c->sid[0]) {
+			rc = sepol_sidtab_context_to_sid(sidtab,
+							 &c->context[0],
+							 &c->sid[0]);
+			if (rc)
+				goto out;
+		}
+		*sid = c->sid[0];
+	} else {
+		rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+		if (rc) {
+			*behavior = SECURITY_FS_USE_NONE;
+			rc = 0;
+		} else {
+			*behavior = SECURITY_FS_USE_GENFS;
+		}
+	}
+
+      out:
+	return rc;
+}
+
+/* FLASK */
diff --git a/libsepol/src/sidtab.c b/libsepol/src/sidtab.c
new file mode 100644
index 0000000..5bd7999
--- /dev/null
+++ b/libsepol/src/sidtab.c
@@ -0,0 +1,328 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the SID table type.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <sepol/policydb/sidtab.h>
+
+#include <sepol/policydb/flask.h>
+
+#define SIDTAB_HASH(sid) \
+(sid & SIDTAB_HASH_MASK)
+
+#define INIT_SIDTAB_LOCK(s)
+#define SIDTAB_LOCK(s)
+#define SIDTAB_UNLOCK(s)
+
+int sepol_sidtab_init(sidtab_t * s)
+{
+	int i;
+
+	s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE);
+	if (!s->htable)
+		return -ENOMEM;
+	for (i = 0; i < SIDTAB_SIZE; i++)
+		s->htable[i] = (sidtab_ptr_t) NULL;
+	s->nel = 0;
+	s->next_sid = 1;
+	s->shutdown = 0;
+	INIT_SIDTAB_LOCK(s);
+	return 0;
+}
+
+int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid,
+			context_struct_t * context)
+{
+	int hvalue;
+	sidtab_node_t *prev, *cur, *newnode;
+
+	if (!s || !s->htable)
+		return -ENOMEM;
+
+	hvalue = SIDTAB_HASH(sid);
+	prev = NULL;
+	cur = s->htable[hvalue];
+	while (cur != NULL && sid > cur->sid) {
+		prev = cur;
+		cur = cur->next;
+	}
+
+	if (cur && sid == cur->sid) {
+		errno = EEXIST;
+		return -EEXIST;
+	}
+
+	newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t));
+	if (newnode == NULL)
+		return -ENOMEM;
+	newnode->sid = sid;
+	if (context_cpy(&newnode->context, context)) {
+		free(newnode);
+		return -ENOMEM;
+	}
+
+	if (prev) {
+		newnode->next = prev->next;
+		prev->next = newnode;
+	} else {
+		newnode->next = s->htable[hvalue];
+		s->htable[hvalue] = newnode;
+	}
+
+	s->nel++;
+	if (sid >= s->next_sid)
+		s->next_sid = sid + 1;
+	return 0;
+}
+
+int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid)
+{
+	int hvalue;
+	sidtab_node_t *cur, *last;
+
+	if (!s || !s->htable)
+		return -ENOENT;
+
+	hvalue = SIDTAB_HASH(sid);
+	last = NULL;
+	cur = s->htable[hvalue];
+	while (cur != NULL && sid > cur->sid) {
+		last = cur;
+		cur = cur->next;
+	}
+
+	if (cur == NULL || sid != cur->sid)
+		return -ENOENT;
+
+	if (last == NULL)
+		s->htable[hvalue] = cur->next;
+	else
+		last->next = cur->next;
+
+	context_destroy(&cur->context);
+
+	free(cur);
+	s->nel--;
+	return 0;
+}
+
+context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid)
+{
+	int hvalue;
+	sidtab_node_t *cur;
+
+	if (!s || !s->htable)
+		return NULL;
+
+	hvalue = SIDTAB_HASH(sid);
+	cur = s->htable[hvalue];
+	while (cur != NULL && sid > cur->sid)
+		cur = cur->next;
+
+	if (cur == NULL || sid != cur->sid) {
+		/* Remap invalid SIDs to the unlabeled SID. */
+		sid = SECINITSID_UNLABELED;
+		hvalue = SIDTAB_HASH(sid);
+		cur = s->htable[hvalue];
+		while (cur != NULL && sid > cur->sid)
+			cur = cur->next;
+		if (!cur || sid != cur->sid)
+			return NULL;
+	}
+
+	return &cur->context;
+}
+
+int sepol_sidtab_map(sidtab_t * s,
+		     int (*apply) (sepol_security_id_t sid,
+				   context_struct_t * context,
+				   void *args), void *args)
+{
+	int i, ret;
+	sidtab_node_t *cur;
+
+	if (!s || !s->htable)
+		return 0;
+
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = s->htable[i];
+		while (cur != NULL) {
+			ret = apply(cur->sid, &cur->context, args);
+			if (ret)
+				return ret;
+			cur = cur->next;
+		}
+	}
+	return 0;
+}
+
+void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+				      int (*apply) (sepol_security_id_t sid,
+						    context_struct_t * context,
+						    void *args), void *args)
+{
+	int i, ret;
+	sidtab_node_t *last, *cur, *temp;
+
+	if (!s || !s->htable)
+		return;
+
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		last = NULL;
+		cur = s->htable[i];
+		while (cur != NULL) {
+			ret = apply(cur->sid, &cur->context, args);
+			if (ret) {
+				if (last) {
+					last->next = cur->next;
+				} else {
+					s->htable[i] = cur->next;
+				}
+
+				temp = cur;
+				cur = cur->next;
+				context_destroy(&temp->context);
+				free(temp);
+				s->nel--;
+			} else {
+				last = cur;
+				cur = cur->next;
+			}
+		}
+	}
+
+	return;
+}
+
+static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s,
+							      context_struct_t *
+							      context)
+{
+	int i;
+	sidtab_node_t *cur;
+
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = s->htable[i];
+		while (cur != NULL) {
+			if (context_cmp(&cur->context, context))
+				return cur->sid;
+			cur = cur->next;
+		}
+	}
+	return 0;
+}
+
+int sepol_sidtab_context_to_sid(sidtab_t * s,
+				context_struct_t * context,
+				sepol_security_id_t * out_sid)
+{
+	sepol_security_id_t sid;
+	int ret = 0;
+
+	*out_sid = SEPOL_SECSID_NULL;
+
+	sid = sepol_sidtab_search_context(s, context);
+	if (!sid) {
+		SIDTAB_LOCK(s);
+		/* Rescan now that we hold the lock. */
+		sid = sepol_sidtab_search_context(s, context);
+		if (sid)
+			goto unlock_out;
+		/* No SID exists for the context.  Allocate a new one. */
+		if (s->next_sid == UINT_MAX || s->shutdown) {
+			ret = -ENOMEM;
+			goto unlock_out;
+		}
+		sid = s->next_sid++;
+		ret = sepol_sidtab_insert(s, sid, context);
+		if (ret)
+			s->next_sid--;
+	      unlock_out:
+		SIDTAB_UNLOCK(s);
+	}
+
+	if (ret)
+		return ret;
+
+	*out_sid = sid;
+	return 0;
+}
+
+void sepol_sidtab_hash_eval(sidtab_t * h, char *tag)
+{
+	int i, chain_len, slots_used, max_chain_len;
+	sidtab_node_t *cur;
+
+	slots_used = 0;
+	max_chain_len = 0;
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = h->htable[i];
+		if (cur) {
+			slots_used++;
+			chain_len = 0;
+			while (cur) {
+				chain_len++;
+				cur = cur->next;
+			}
+
+			if (chain_len > max_chain_len)
+				max_chain_len = chain_len;
+		}
+	}
+
+	printf
+	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
+	     tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len);
+}
+
+void sepol_sidtab_destroy(sidtab_t * s)
+{
+	int i;
+	sidtab_ptr_t cur, temp;
+
+	if (!s || !s->htable)
+		return;
+
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = s->htable[i];
+		while (cur != NULL) {
+			temp = cur;
+			cur = cur->next;
+			context_destroy(&temp->context);
+			free(temp);
+		}
+		s->htable[i] = NULL;
+	}
+	free(s->htable);
+	s->htable = NULL;
+	s->nel = 0;
+	s->next_sid = 1;
+}
+
+void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src)
+{
+	SIDTAB_LOCK(src);
+	dst->htable = src->htable;
+	dst->nel = src->nel;
+	dst->next_sid = src->next_sid;
+	dst->shutdown = 0;
+	SIDTAB_UNLOCK(src);
+}
+
+void sepol_sidtab_shutdown(sidtab_t * s)
+{
+	SIDTAB_LOCK(s);
+	s->shutdown = 1;
+	SIDTAB_UNLOCK(s);
+}
+
+/* FLASK */
diff --git a/libsepol/src/symtab.c b/libsepol/src/symtab.c
new file mode 100644
index 0000000..b319c8f
--- /dev/null
+++ b/libsepol/src/symtab.c
@@ -0,0 +1,57 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the symbol table type.
+ */
+
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/symtab.h>
+
+static unsigned int symhash(hashtab_t h, hashtab_key_t key)
+{
+	char *p, *keyp;
+	size_t size;
+	unsigned int val;
+
+	val = 0;
+	keyp = (char *)key;
+	size = strlen(keyp);
+	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+		val =
+		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+	return val & (h->size - 1);
+}
+
+static int symcmp(hashtab_t h
+		  __attribute__ ((unused)), hashtab_key_t key1,
+		  hashtab_key_t key2)
+{
+	char *keyp1, *keyp2;
+
+	keyp1 = (char *)key1;
+	keyp2 = (char *)key2;
+	return strcmp(keyp1, keyp2);
+}
+
+int symtab_init(symtab_t * s, unsigned int size)
+{
+	s->table = hashtab_create(symhash, symcmp, size);
+	if (!s->table)
+		return -1;
+	s->nprim = 0;
+	return 0;
+}
+
+void symtab_destroy(symtab_t * s)
+{
+	if (!s)
+		return;
+	if (s->table)
+		hashtab_destroy(s->table);
+	return;
+}
+/* FLASK */
diff --git a/libsepol/src/user_internal.h b/libsepol/src/user_internal.h
new file mode 100644
index 0000000..7523b7d
--- /dev/null
+++ b/libsepol/src/user_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_USER_INTERNAL_H_
+#define _SEPOL_USER_INTERNAL_H_
+
+#include <sepol/user_record.h>
+#include <sepol/users.h>
+#include "dso.h"
+
+hidden_proto(sepol_user_add_role)
+    hidden_proto(sepol_user_create)
+    hidden_proto(sepol_user_free)
+    hidden_proto(sepol_user_get_mlslevel)
+    hidden_proto(sepol_user_get_mlsrange)
+    hidden_proto(sepol_user_get_roles)
+    hidden_proto(sepol_user_has_role)
+    hidden_proto(sepol_user_key_create)
+    hidden_proto(sepol_user_key_unpack)
+    hidden_proto(sepol_user_set_mlslevel)
+    hidden_proto(sepol_user_set_mlsrange)
+    hidden_proto(sepol_user_set_name)
+#endif
diff --git a/libsepol/src/user_record.c b/libsepol/src/user_record.c
new file mode 100644
index 0000000..c59c54b
--- /dev/null
+++ b/libsepol/src/user_record.c
@@ -0,0 +1,379 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "user_internal.h"
+#include "debug.h"
+
+struct sepol_user {
+	/* This user's name */
+	char *name;
+
+	/* This user's mls level (only required for mls) */
+	char *mls_level;
+
+	/* This user's mls range (only required for mls) */
+	char *mls_range;
+
+	/* The role array */
+	char **roles;
+
+	/* The number of roles */
+	unsigned int num_roles;
+};
+
+struct sepol_user_key {
+	/* This user's name */
+	const char *name;
+};
+
+int sepol_user_key_create(sepol_handle_t * handle,
+			  const char *name, sepol_user_key_t ** key_ptr)
+{
+
+	sepol_user_key_t *tmp_key =
+	    (sepol_user_key_t *) malloc(sizeof(sepol_user_key_t));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, "
+		    "could not create selinux user key");
+		return STATUS_ERR;
+	}
+
+	tmp_key->name = name;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_key_create)
+
+void sepol_user_key_unpack(const sepol_user_key_t * key, const char **name)
+{
+
+	*name = key->name;
+}
+
+hidden_def(sepol_user_key_unpack)
+
+int sepol_user_key_extract(sepol_handle_t * handle,
+			   const sepol_user_t * user,
+			   sepol_user_key_t ** key_ptr)
+{
+
+	if (sepol_user_key_create(handle, user->name, key_ptr) < 0) {
+		ERR(handle, "could not extract key from user %s", user->name);
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_user_key_free(sepol_user_key_t * key)
+{
+	free(key);
+}
+
+int sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key)
+{
+
+	return strcmp(user->name, key->name);
+}
+
+int sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2)
+{
+
+	return strcmp(user->name, user2->name);
+}
+
+/* Name */
+const char *sepol_user_get_name(const sepol_user_t * user)
+{
+
+	return user->name;
+}
+
+int sepol_user_set_name(sepol_handle_t * handle,
+			sepol_user_t * user, const char *name)
+{
+
+	char *tmp_name = strdup(name);
+	if (!tmp_name) {
+		ERR(handle, "out of memory, could not set name");
+		return STATUS_ERR;
+	}
+	free(user->name);
+	user->name = tmp_name;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_name)
+
+/* MLS */
+const char *sepol_user_get_mlslevel(const sepol_user_t * user)
+{
+
+	return user->mls_level;
+}
+
+hidden_def(sepol_user_get_mlslevel)
+
+int sepol_user_set_mlslevel(sepol_handle_t * handle,
+			    sepol_user_t * user, const char *mls_level)
+{
+
+	char *tmp_mls_level = strdup(mls_level);
+	if (!tmp_mls_level) {
+		ERR(handle, "out of memory, "
+		    "could not set MLS default level");
+		return STATUS_ERR;
+	}
+	free(user->mls_level);
+	user->mls_level = tmp_mls_level;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlslevel)
+
+const char *sepol_user_get_mlsrange(const sepol_user_t * user)
+{
+
+	return user->mls_range;
+}
+
+hidden_def(sepol_user_get_mlsrange)
+
+int sepol_user_set_mlsrange(sepol_handle_t * handle,
+			    sepol_user_t * user, const char *mls_range)
+{
+
+	char *tmp_mls_range = strdup(mls_range);
+	if (!tmp_mls_range) {
+		ERR(handle, "out of memory, "
+		    "could not set MLS allowed range");
+		return STATUS_ERR;
+	}
+	free(user->mls_range);
+	user->mls_range = tmp_mls_range;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlsrange)
+
+/* Roles */
+int sepol_user_get_num_roles(const sepol_user_t * user)
+{
+
+	return user->num_roles;
+}
+
+int sepol_user_add_role(sepol_handle_t * handle,
+			sepol_user_t * user, const char *role)
+{
+
+	char *role_cp;
+	char **roles_realloc;
+
+	if (sepol_user_has_role(user, role))
+		return STATUS_SUCCESS;
+
+	role_cp = strdup(role);
+	roles_realloc = realloc(user->roles,
+				sizeof(char *) * (user->num_roles + 1));
+
+	if (!role_cp || !roles_realloc)
+		goto omem;
+
+	user->num_roles++;
+	user->roles = roles_realloc;
+	user->roles[user->num_roles - 1] = role_cp;
+
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not add role %s", role);
+	free(role_cp);
+	free(roles_realloc);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_user_add_role)
+
+int sepol_user_has_role(const sepol_user_t * user, const char *role)
+{
+
+	unsigned int i;
+
+	for (i = 0; i < user->num_roles; i++)
+		if (!strcmp(user->roles[i], role))
+			return 1;
+	return 0;
+}
+
+hidden_def(sepol_user_has_role)
+
+int sepol_user_set_roles(sepol_handle_t * handle,
+			 sepol_user_t * user,
+			 const char **roles_arr, unsigned int num_roles)
+{
+
+	unsigned int i;
+	char **tmp_roles = NULL;
+
+	if (num_roles > 0) {
+
+		/* First, make a copy */
+		tmp_roles = (char **)calloc(1, sizeof(char *) * num_roles);
+		if (!tmp_roles)
+			goto omem;
+
+		for (i = 0; i < num_roles; i++) {
+			tmp_roles[i] = strdup(roles_arr[i]);
+			if (!tmp_roles[i])
+				goto omem;
+		}
+	}
+
+	/* Apply other changes */
+	for (i = 0; i < user->num_roles; i++)
+		free(user->roles[i]);
+	free(user->roles);
+	user->roles = tmp_roles;
+	user->num_roles = num_roles;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not allocate roles array for"
+	    "user %s", user->name);
+
+	if (tmp_roles) {
+		for (i = 0; i < num_roles; i++) {
+			if (!tmp_roles[i])
+				break;
+			free(tmp_roles[i]);
+		}
+	}
+	free(tmp_roles);
+	return STATUS_ERR;
+}
+
+int sepol_user_get_roles(sepol_handle_t * handle,
+			 const sepol_user_t * user,
+			 const char ***roles_arr, unsigned int *num_roles)
+{
+
+	unsigned int i;
+	const char **tmp_roles =
+	    (const char **)malloc(sizeof(char *) * user->num_roles);
+	if (!tmp_roles)
+		goto omem;
+
+	for (i = 0; i < user->num_roles; i++)
+		tmp_roles[i] = user->roles[i];
+
+	*roles_arr = tmp_roles;
+	*num_roles = user->num_roles;
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory, could not "
+	    "allocate roles array for user %s", user->name);
+	free(tmp_roles);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_user_get_roles)
+
+void sepol_user_del_role(sepol_user_t * user, const char *role)
+{
+
+	unsigned int i;
+	for (i = 0; i < user->num_roles; i++) {
+		if (!strcmp(user->roles[i], role)) {
+			free(user->roles[i]);
+			user->roles[i] = NULL;
+			user->roles[i] = user->roles[user->num_roles - 1];
+			user->num_roles--;
+		}
+	}
+}
+
+/* Create */
+int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr)
+{
+
+	sepol_user_t *user = (sepol_user_t *) malloc(sizeof(sepol_user_t));
+
+	if (!user) {
+		ERR(handle, "out of memory, "
+		    "could not create selinux user record");
+		return STATUS_ERR;
+	}
+
+	user->roles = NULL;
+	user->num_roles = 0;
+	user->name = NULL;
+	user->mls_level = NULL;
+	user->mls_range = NULL;
+
+	*user_ptr = user;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_create)
+
+/* Deep copy clone */
+int sepol_user_clone(sepol_handle_t * handle,
+		     const sepol_user_t * user, sepol_user_t ** user_ptr)
+{
+
+	sepol_user_t *new_user = NULL;
+	unsigned int i;
+
+	if (sepol_user_create(handle, &new_user) < 0)
+		goto err;
+
+	if (sepol_user_set_name(handle, new_user, user->name) < 0)
+		goto err;
+
+	for (i = 0; i < user->num_roles; i++) {
+		if (sepol_user_add_role(handle, new_user, user->roles[i]) < 0)
+			goto err;
+	}
+
+	if (user->mls_level &&
+	    (sepol_user_set_mlslevel(handle, new_user, user->mls_level) < 0))
+		goto err;
+
+	if (user->mls_range &&
+	    (sepol_user_set_mlsrange(handle, new_user, user->mls_range) < 0))
+		goto err;
+
+	*user_ptr = new_user;
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not clone selinux user record");
+	sepol_user_free(new_user);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_user_free(sepol_user_t * user)
+{
+
+	unsigned int i;
+
+	if (!user)
+		return;
+
+	free(user->name);
+	for (i = 0; i < user->num_roles; i++)
+		free(user->roles[i]);
+	free(user->roles);
+	free(user->mls_level);
+	free(user->mls_range);
+	free(user);
+}
+
+hidden_def(sepol_user_free)
diff --git a/libsepol/src/users.c b/libsepol/src/users.c
new file mode 100644
index 0000000..ce54c2b
--- /dev/null
+++ b/libsepol/src/users.c
@@ -0,0 +1,381 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "private.h"
+#include "debug.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include "user_internal.h"
+#include "mls.h"
+
+static int user_to_record(sepol_handle_t * handle,
+			  const policydb_t * policydb,
+			  int user_idx, sepol_user_t ** record)
+{
+
+	const char *name = policydb->p_user_val_to_name[user_idx];
+	user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx];
+	ebitmap_t *roles = &(usrdatum->roles.roles);
+	ebitmap_node_t *rnode;
+	unsigned bit;
+
+	sepol_user_t *tmp_record = NULL;
+
+	if (sepol_user_create(handle, &tmp_record) < 0)
+		goto err;
+
+	if (sepol_user_set_name(handle, tmp_record, name) < 0)
+		goto err;
+
+	/* Extract roles */
+	ebitmap_for_each_bit(roles, rnode, bit) {
+		if (ebitmap_node_get_bit(rnode, bit)) {
+			char *role = policydb->p_role_val_to_name[bit];
+			if (sepol_user_add_role(handle, tmp_record, role) < 0)
+				goto err;
+		}
+	}
+
+	/* Extract MLS info */
+	if (policydb->mls) {
+		context_struct_t context;
+		char *str;
+
+		context_init(&context);
+		if (mls_level_cpy(&context.range.level[0],
+				  &usrdatum->exp_dfltlevel) < 0) {
+			ERR(handle, "could not copy MLS level");
+			context_destroy(&context);
+			goto err;
+		}
+		if (mls_level_cpy(&context.range.level[1],
+				  &usrdatum->exp_dfltlevel) < 0) {
+			ERR(handle, "could not copy MLS level");
+			context_destroy(&context);
+			goto err;
+		}
+		if (mls_to_string(handle, policydb, &context, &str) < 0) {
+			context_destroy(&context);
+			goto err;
+		}
+		context_destroy(&context);
+
+		if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) {
+			free(str);
+			goto err;
+		}
+		free(str);
+
+		context_init(&context);
+		if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) {
+			ERR(handle, "could not copy MLS range");
+			context_destroy(&context);
+			goto err;
+		}
+		if (mls_to_string(handle, policydb, &context, &str) < 0) {
+			context_destroy(&context);
+			goto err;
+		}
+		context_destroy(&context);
+
+		if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) {
+			free(str);
+			goto err;
+		}
+		free(str);
+	}
+
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+      err:
+	/* FIXME: handle error */
+	sepol_user_free(tmp_record);
+	return STATUS_ERR;
+}
+
+int sepol_user_modify(sepol_handle_t * handle,
+		      sepol_policydb_t * p,
+		      const sepol_user_key_t * key, const sepol_user_t * user)
+{
+
+	policydb_t *policydb = &p->p;
+
+	/* For user data */
+	const char *cname, *cmls_level, *cmls_range;
+	char *name = NULL;
+
+	const char **roles = NULL;
+	unsigned int num_roles = 0;
+
+	/* Low-level representation */
+	user_datum_t *usrdatum = NULL;
+	role_datum_t *roldatum;
+	unsigned int i;
+
+	context_struct_t context;
+	unsigned bit;
+	int new = 0;
+
+	ebitmap_node_t *rnode;
+
+	/* First, extract all the data */
+	sepol_user_key_unpack(key, &cname);
+
+	cmls_level = sepol_user_get_mlslevel(user);
+	cmls_range = sepol_user_get_mlsrange(user);
+
+	/* Make sure that worked properly */
+	if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0)
+		goto err;
+
+	/* Now, see if a user exists */
+	usrdatum = hashtab_search(policydb->p_users.table,
+				  (const hashtab_key_t)cname);
+
+	/* If it does, we will modify it */
+	if (usrdatum) {
+
+		int value_cp = usrdatum->s.value;
+		user_datum_destroy(usrdatum);
+		user_datum_init(usrdatum);
+		usrdatum->s.value = value_cp;
+
+		/* Otherwise, create a new one */
+	} else {
+		usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
+		if (!usrdatum)
+			goto omem;
+		user_datum_init(usrdatum);
+		new = 1;
+	}
+
+	/* For every role */
+	for (i = 0; i < num_roles; i++) {
+
+		/* Search for the role */
+		roldatum = hashtab_search(policydb->p_roles.table,
+					  (const hashtab_key_t)roles[i]);
+		if (!roldatum) {
+			ERR(handle, "undefined role %s for user %s",
+			    roles[i], cname);
+			goto err;
+		}
+
+		/* Set the role and every role it dominates */
+		ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+			if (ebitmap_node_get_bit(rnode, bit)) {
+				if (ebitmap_set_bit
+				    (&(usrdatum->roles.roles), bit, 1))
+					goto omem;
+			}
+		}
+	}
+
+	/* For MLS systems */
+	if (policydb->mls) {
+
+		/* MLS level */
+		if (cmls_level == NULL) {
+			ERR(handle, "MLS is enabled, but no MLS "
+			    "default level was defined for user %s", cname);
+			goto err;
+		}
+
+		context_init(&context);
+		if (mls_from_string(handle, policydb, cmls_level, &context) < 0) {
+			context_destroy(&context);
+			goto err;
+		}
+		if (mls_level_cpy(&usrdatum->exp_dfltlevel,
+				  &context.range.level[0]) < 0) {
+			ERR(handle, "could not copy MLS level %s", cmls_level);
+			context_destroy(&context);
+			goto err;
+		}
+		context_destroy(&context);
+
+		/* MLS range */
+		if (cmls_range == NULL) {
+			ERR(handle, "MLS is enabled, but no MLS"
+			    "range was defined for user %s", cname);
+			goto err;
+		}
+
+		context_init(&context);
+		if (mls_from_string(handle, policydb, cmls_range, &context) < 0) {
+			context_destroy(&context);
+			goto err;
+		}
+		if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) {
+			ERR(handle, "could not copy MLS range %s", cmls_range);
+			context_destroy(&context);
+			goto err;
+		}
+		context_destroy(&context);
+	} else if (cmls_level != NULL || cmls_range != NULL) {
+		ERR(handle, "MLS is disabled, but MLS level/range "
+		    "was found for user %s", cname);
+		goto err;
+	}
+
+	/* If there are no errors, and this is a new user, add the user to policy */
+	if (new) {
+		void *tmp_ptr;
+
+		/* Ensure reverse lookup array has enough space */
+		tmp_ptr = realloc(policydb->user_val_to_struct,
+				  (policydb->p_users.nprim +
+				   1) * sizeof(user_datum_t *));
+		if (!tmp_ptr)
+			goto omem;
+		policydb->user_val_to_struct = tmp_ptr;
+
+		tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS],
+				  (policydb->p_users.nprim +
+				   1) * sizeof(char *));
+		if (!tmp_ptr)
+			goto omem;
+		policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
+
+		/* Need to copy the user name */
+		name = strdup(cname);
+		if (!name)
+			goto omem;
+
+		/* Store user */
+		usrdatum->s.value = ++policydb->p_users.nprim;
+		if (hashtab_insert(policydb->p_users.table, name,
+				   (hashtab_datum_t) usrdatum) < 0)
+			goto omem;
+
+		/* Set up reverse entry */
+		policydb->p_user_val_to_name[usrdatum->s.value - 1] = name;
+		policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+		name = NULL;
+
+		/* Expand roles */
+		if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
+				    policydb, NULL, NULL)) {
+			ERR(handle, "unable to expand role set");
+			goto err;
+		}
+	}
+
+	free(roles);
+	return STATUS_SUCCESS;
+
+      omem:
+	ERR(handle, "out of memory");
+
+      err:
+	ERR(handle, "could not load %s into policy", name);
+
+	free(name);
+	free(roles);
+	if (new && usrdatum) {
+		role_set_destroy(&usrdatum->roles);
+		free(usrdatum);
+	}
+	return STATUS_ERR;
+}
+
+int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)),
+		      const sepol_policydb_t * p,
+		      const sepol_user_key_t * key, int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+
+	const char *cname;
+	sepol_user_key_unpack(key, &cname);
+
+	*response = (hashtab_search(policydb->p_users.table,
+				    (const hashtab_key_t)cname) != NULL);
+
+	return STATUS_SUCCESS;
+}
+
+int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)),
+		     const sepol_policydb_t * p, unsigned int *response)
+{
+
+	const policydb_t *policydb = &p->p;
+	*response = policydb->p_users.nprim;
+
+	return STATUS_SUCCESS;
+}
+
+int sepol_user_query(sepol_handle_t * handle,
+		     const sepol_policydb_t * p,
+		     const sepol_user_key_t * key, sepol_user_t ** response)
+{
+
+	const policydb_t *policydb = &p->p;
+	user_datum_t *usrdatum = NULL;
+
+	const char *cname;
+	sepol_user_key_unpack(key, &cname);
+
+	usrdatum = hashtab_search(policydb->p_users.table,
+				  (const hashtab_key_t)cname);
+
+	if (!usrdatum) {
+		*response = NULL;
+		return STATUS_SUCCESS;
+	}
+
+	if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) <
+	    0)
+		goto err;
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not query user %s", cname);
+	return STATUS_ERR;
+}
+
+int sepol_user_iterate(sepol_handle_t * handle,
+		       const sepol_policydb_t * p,
+		       int (*fn) (const sepol_user_t * user,
+				  void *fn_arg), void *arg)
+{
+
+	const policydb_t *policydb = &p->p;
+	unsigned int nusers = policydb->p_users.nprim;
+	sepol_user_t *user = NULL;
+	unsigned int i;
+
+	/* For each user */
+	for (i = 0; i < nusers; i++) {
+
+		int status;
+
+		if (user_to_record(handle, policydb, i, &user) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(user, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_user_free(user);
+		user = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+      err:
+	ERR(handle, "could not iterate over users");
+	sepol_user_free(user);
+	return STATUS_ERR;
+}
diff --git a/libsepol/src/util.c b/libsepol/src/util.c
new file mode 100644
index 0000000..ff8f7f2
--- /dev/null
+++ b/libsepol/src/util.c
@@ -0,0 +1,286 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * 	    Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005-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 <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/util.h>
+#include <dso.h>
+
+struct val_to_name {
+	unsigned int val;
+	char *name;
+};
+
+/* Add an unsigned integer to a dynamically reallocated array.  *cnt
+ * is a reference pointer to the number of values already within array
+ * *a; it will be incremented upon successfully appending i.  If *a is
+ * NULL then this function will create a new array (*cnt is reset to
+ * 0).  Return 0 on success, -1 on out of memory. */
+int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
+{
+	if (cnt == NULL || a == NULL)
+		return -1;
+
+	/* FIX ME: This is not very elegant! We use an array that we
+	 * grow as new uint32_t are added to an array.  But rather
+	 * than be smart about it, for now we realloc() the array each
+	 * time a new uint32_t is added! */
+	if (*a != NULL)
+		*a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
+	else {			/* empty list */
+
+		*cnt = 0;
+		*a = (uint32_t *) malloc(sizeof(uint32_t));
+	}
+	if (*a == NULL) {
+		return -1;
+	}
+	(*a)[*cnt] = i;
+	(*cnt)++;
+	return 0;
+}
+
+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	struct val_to_name *v = data;
+	perm_datum_t *perdatum;
+
+	perdatum = (perm_datum_t *) datum;
+
+	if (v->val == perdatum->s.value) {
+		v->name = key;
+		return 1;
+	}
+
+	return 0;
+}
+
+char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+			 sepol_access_vector_t av)
+{
+	struct val_to_name v;
+	static char avbuf[1024];
+	class_datum_t *cladatum;
+	char *perm = NULL, *p;
+	unsigned int i;
+	int rc;
+	int avlen = 0, len;
+
+	cladatum = policydbp->class_val_to_struct[tclass - 1];
+	p = avbuf;
+	for (i = 0; i < cladatum->permissions.nprim; i++) {
+		if (av & (1 << i)) {
+			v.val = i + 1;
+			rc = hashtab_map(cladatum->permissions.table,
+					 perm_name, &v);
+			if (!rc && cladatum->comdatum) {
+				rc = hashtab_map(cladatum->comdatum->
+						 permissions.table, perm_name,
+						 &v);
+			}
+			if (rc)
+				perm = v.name;
+			if (perm) {
+				len =
+				    snprintf(p, sizeof(avbuf) - avlen, " %s",
+					     perm);
+				if (len < 0
+				    || (size_t) len >= (sizeof(avbuf) - avlen))
+					return NULL;
+				p += len;
+				avlen += len;
+			}
+		}
+	}
+
+	return avbuf;
+}
+
+#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
+
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
+{
+	uint16_t value;
+	uint16_t low_bit;
+	uint16_t low_value;
+	unsigned int bit;
+	unsigned int in_range = 0;
+	static char xpermsbuf[2048];
+	xpermsbuf[0] = '\0';
+	char *p;
+	int len, xpermslen = 0;
+	p = xpermsbuf;
+
+	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+		return NULL;
+
+	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
+	p += len;
+	xpermslen += len;
+
+	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
+		if (!xperm_test(bit, xperms->perms))
+			continue;
+
+		if (in_range && next_bit_in_range(bit, xperms->perms)) {
+			/* continue until high value found */
+			continue;
+		} else if (next_bit_in_range(bit, xperms->perms)) {
+			/* low value */
+			low_bit = bit;
+			in_range = 1;
+			continue;
+		}
+
+		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
+			value = xperms->driver<<8 | bit;
+			low_value = xperms->driver<<8 | low_bit;
+			if (in_range) {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
+			} else {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
+			}
+		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
+			value = bit << 8;
+			low_value = low_bit << 8;
+			if (in_range) {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
+			} else {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
+			}
+
+		}
+
+		if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+			return NULL;
+
+		p += len;
+		xpermslen += len;
+		if (in_range)
+			in_range = 0;
+	}
+
+	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
+	if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+		return NULL;
+
+	return xpermsbuf;
+}
+
+/*
+ * The tokenize and tokenize_str functions may be used to
+ * replace sscanf to read tokens from buffers.
+ */
+
+/* Read a token from a buffer */
+static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
+{
+	char *tmp_buf = *ptr;
+	*str = NULL;
+
+	while (**ptr != '\0') {
+		if (isspace(delim) && isspace(**ptr)) {
+			(*ptr)++;
+			break;
+		} else if (!isspace(delim) && **ptr == delim) {
+			(*ptr)++;
+			break;
+		}
+
+		(*ptr)++;
+	}
+
+	*len = *ptr - tmp_buf;
+	/* If the end of the string has not been reached, this will ensure the
+	 * delimiter is not included when returning the token.
+	 */
+	if (**ptr != '\0') {
+		(*len)--;
+	}
+
+	*str = strndup(tmp_buf, *len);
+	if (!*str) {
+		return -1;
+	}
+
+	/* Squash spaces if the delimiter is a whitespace character */
+	while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
+		(*ptr)++;
+	}
+
+	return 0;
+}
+
+/*
+ * line_buf - Buffer containing string to tokenize.
+ * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
+ *	    be tokenized using isspace().
+ * num_args - The number of parameter entries to process.
+ * ...      - A 'char **' for each parameter.
+ * returns  - The number of items processed.
+ *
+ * This function calls tokenize_str() to do the actual string processing. The
+ * caller is responsible for calling free() on each additional argument. The
+ * function will not tokenize more than num_args and the last argument will
+ * contain the remaining content of line_buf. If the delimiter is any whitespace
+ * character, then all whitespace will be squashed.
+ */
+int hidden tokenize(char *line_buf, char delim, int num_args, ...)
+{
+	char **arg, *buf_p;
+	int rc, items;
+	size_t arg_len = 0;
+	va_list ap;
+
+	buf_p = line_buf;
+
+	/* Process the arguments */
+	va_start(ap, num_args);
+
+	for (items = 0; items < num_args && *buf_p != '\0'; items++) {
+		arg = va_arg(ap, char **);
+
+		/* Save the remainder of the string in arg */
+		if (items == num_args - 1) {
+			*arg = strdup(buf_p);
+			if (*arg == NULL) {
+				goto exit;
+			}
+
+			continue;
+		}
+
+		rc = tokenize_str(delim, arg, &buf_p, &arg_len);
+		if (rc < 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	va_end(ap);
+	return items;
+}
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
new file mode 100644
index 0000000..d87ea61
--- /dev/null
+++ b/libsepol/src/write.c
@@ -0,0 +1,2166 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *	Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * 	Added conditional policy language extensions
+ * 
+ * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org>
+ *
+ *	Module writing support
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003-2005 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 <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask.h>
+
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+struct policy_data {
+	struct policy_file *fp;
+	struct policydb *p;
+};
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp);
+
+static int ebitmap_write(ebitmap_t * e, struct policy_file *fp)
+{
+	ebitmap_node_t *n;
+	uint32_t buf[32], bit, count;
+	uint64_t map;
+	size_t items;
+
+	buf[0] = cpu_to_le32(MAPSIZE);
+	buf[1] = cpu_to_le32(e->highbit);
+
+	count = 0;
+	for (n = e->node; n; n = n->next)
+		count++;
+	buf[2] = cpu_to_le32(count);
+
+	items = put_entry(buf, sizeof(uint32_t), 3, fp);
+	if (items != 3)
+		return POLICYDB_ERROR;
+
+	for (n = e->node; n; n = n->next) {
+		bit = cpu_to_le32(n->startbit);
+		items = put_entry(&bit, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		map = cpu_to_le64(n->map);
+		items = put_entry(&map, sizeof(uint64_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+	AVTAB_ALLOWED,
+	AVTAB_AUDITDENY,
+	AVTAB_AUDITALLOW,
+	AVTAB_TRANSITION,
+	AVTAB_CHANGE,
+	AVTAB_MEMBER
+};
+
+static int avtab_write_item(policydb_t * p,
+			    avtab_ptr_t cur, struct policy_file *fp,
+			    unsigned merge, unsigned commit, uint32_t * nel)
+{
+	avtab_ptr_t node;
+	uint8_t buf8;
+	uint16_t buf16[4];
+	uint32_t buf32[10], lookup, val;
+	size_t items, items2;
+	unsigned set;
+	unsigned int oldvers = (p->policy_type == POLICY_KERN
+				&& p->policyvers < POLICYDB_VERSION_AVTAB);
+	unsigned int i;
+
+	if (oldvers) {
+		/* Generate the old avtab format.
+		   Requires merging similar entries if uncond avtab. */
+		if (merge) {
+			if (cur->merged)
+				return POLICYDB_SUCCESS;	/* already merged by prior merge */
+		}
+
+		items = 1;	/* item 0 is used for the item count */
+		val = cur->key.source_type;
+		buf32[items++] = cpu_to_le32(val);
+		val = cur->key.target_type;
+		buf32[items++] = cpu_to_le32(val);
+		val = cur->key.target_class;
+		buf32[items++] = cpu_to_le32(val);
+
+		val = cur->key.specified & ~AVTAB_ENABLED;
+		if (cur->key.specified & AVTAB_ENABLED)
+			val |= AVTAB_ENABLED_OLD;
+		set = 1;
+
+		if (merge) {
+			/* Merge specifier values for all similar (av or type)
+			   entries that have the same key. */
+			if (val & AVTAB_AV)
+				lookup = AVTAB_AV;
+			else if (val & AVTAB_TYPE)
+				lookup = AVTAB_TYPE;
+			else
+				return POLICYDB_ERROR;
+			for (node = avtab_search_node_next(cur, lookup);
+			     node;
+			     node = avtab_search_node_next(node, lookup)) {
+				val |= (node->key.specified & ~AVTAB_ENABLED);
+				set++;
+				if (node->key.specified & AVTAB_ENABLED)
+					val |= AVTAB_ENABLED_OLD;
+			}
+		}
+
+		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+			ERR(fp->handle, "null entry");
+			return POLICYDB_ERROR;
+		}
+		if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+			ERR(fp->handle, "entry has both access "
+			    "vectors and types");
+			return POLICYDB_ERROR;
+		}
+
+		buf32[items++] = cpu_to_le32(val);
+
+		if (merge) {
+			/* Include datums for all similar (av or type)
+			   entries that have the same key. */
+			for (i = 0;
+			     i < (sizeof(spec_order) / sizeof(spec_order[0]));
+			     i++) {
+				if (val & spec_order[i]) {
+					if (cur->key.specified & spec_order[i])
+						node = cur;
+					else {
+						node =
+						    avtab_search_node_next(cur,
+									   spec_order
+									   [i]);
+						if (nel)
+							(*nel)--;	/* one less node */
+					}
+
+					if (!node) {
+						ERR(fp->handle, "missing node");
+						return POLICYDB_ERROR;
+					}
+					buf32[items++] =
+					    cpu_to_le32(node->datum.data);
+					set--;
+					node->merged = 1;
+				}
+			}
+		} else {
+			buf32[items++] = cpu_to_le32(cur->datum.data);
+			cur->merged = 1;
+			set--;
+		}
+
+		if (set) {
+			ERR(fp->handle, "data count wrong");
+			return POLICYDB_ERROR;
+		}
+
+		buf32[0] = cpu_to_le32(items - 1);
+
+		if (commit) {
+			/* Commit this item to the policy file. */
+			items2 = put_entry(buf32, sizeof(uint32_t), items, fp);
+			if (items != items2)
+				return POLICYDB_ERROR;
+		}
+
+		return POLICYDB_SUCCESS;
+	}
+
+	/* Generate the new avtab format. */
+	buf16[0] = cpu_to_le16(cur->key.source_type);
+	buf16[1] = cpu_to_le16(cur->key.target_type);
+	buf16[2] = cpu_to_le16(cur->key.target_class);
+	buf16[3] = cpu_to_le16(cur->key.specified);
+	items = put_entry(buf16, sizeof(uint16_t), 4, fp);
+	if (items != 4)
+		return POLICYDB_ERROR;
+	if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+			(cur->key.specified & AVTAB_XPERMS)) {
+		ERR(fp->handle, "policy version %u does not support ioctl extended"
+				"permissions rules and one was specified", p->policyvers);
+		return POLICYDB_ERROR;
+	}
+
+	if (p->target_platform != SEPOL_TARGET_SELINUX &&
+			(cur->key.specified & AVTAB_XPERMS)) {
+		ERR(fp->handle, "Target platform %s does not support ioctl "
+				"extended permissions rules and one was specified",
+				policydb_target_strings[p->target_platform]);
+		return POLICYDB_ERROR;
+	}
+
+	if (cur->key.specified & AVTAB_XPERMS) {
+		buf8 = cur->datum.xperms->specified;
+		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		buf8 = cur->datum.xperms->driver;
+		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
+			buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
+		items = put_entry(buf32, sizeof(uint32_t),8,fp);
+		if (items != 8)
+			return POLICYDB_ERROR;
+	} else {
+		buf32[0] = cpu_to_le32(cur->datum.data);
+		items = put_entry(buf32, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static inline void avtab_reset_merged(avtab_t * a)
+{
+	unsigned int i;
+	avtab_ptr_t cur;
+	for (i = 0; i < a->nslot; i++) {
+		for (cur = a->htable[i]; cur; cur = cur->next)
+			cur->merged = 0;
+	}
+}
+
+static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
+{
+	unsigned int i;
+	int rc;
+	avtab_t expa;
+	avtab_ptr_t cur;
+	uint32_t nel;
+	size_t items;
+	unsigned int oldvers = (p->policy_type == POLICY_KERN
+				&& p->policyvers < POLICYDB_VERSION_AVTAB);
+
+	if (oldvers) {
+		/* Old avtab format.
+		   First, we need to expand attributes.  Then, we need to
+		   merge similar entries, so we need to track merged nodes 
+		   and compute the final nel. */
+		if (avtab_init(&expa))
+			return POLICYDB_ERROR;
+		if (expand_avtab(p, a, &expa)) {
+			rc = -1;
+			goto out;
+		}
+		a = &expa;
+		avtab_reset_merged(a);
+		nel = a->nel;
+	} else {
+		/* New avtab format.  nel is good to go. */
+		nel = cpu_to_le32(a->nel);
+		items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+
+	for (i = 0; i < a->nslot; i++) {
+		for (cur = a->htable[i]; cur; cur = cur->next) {
+			/* If old format, compute final nel.
+			   If new format, write out the items. */
+			if (avtab_write_item(p, cur, fp, 1, !oldvers, &nel)) {
+				rc = -1;
+				goto out;
+			}
+		}
+	}
+
+	if (oldvers) {
+		/* Old avtab format.
+		   Write the computed nel value, then write the items. */
+		nel = cpu_to_le32(nel);
+		items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+		if (items != 1) {
+			rc = -1;
+			goto out;
+		}
+		avtab_reset_merged(a);
+		for (i = 0; i < a->nslot; i++) {
+			for (cur = a->htable[i]; cur; cur = cur->next) {
+				if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
+					rc = -1;
+					goto out;
+				}
+			}
+		}
+	}
+
+	rc = 0;
+      out:
+	if (oldvers)
+		avtab_destroy(&expa);
+	return rc;
+}
+
+/*
+ * Write a semantic MLS level structure to a policydb binary 
+ * representation file.
+ */
+static int mls_write_semantic_level_helper(mls_semantic_level_t * l,
+					   struct policy_file *fp)
+{
+	uint32_t buf[2], ncat = 0;
+	size_t items;
+	mls_semantic_cat_t *cat;
+
+	for (cat = l->cat; cat; cat = cat->next)
+		ncat++;
+
+	buf[0] = cpu_to_le32(l->sens);
+	buf[1] = cpu_to_le32(ncat);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+
+	for (cat = l->cat; cat; cat = cat->next) {
+		buf[0] = cpu_to_le32(cat->low);
+		buf[1] = cpu_to_le32(cat->high);
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+/*
+ * Read a semantic MLS range structure to a policydb binary 
+ * representation file.
+ */
+static int mls_write_semantic_range_helper(mls_semantic_range_t * r,
+					   struct policy_file *fp)
+{
+	int rc;
+
+	rc = mls_write_semantic_level_helper(&r->level[0], fp);
+	if (rc)
+		return rc;
+
+	rc = mls_write_semantic_level_helper(&r->level[1], fp);
+
+	return rc;
+}
+
+/*
+ * Write a MLS level structure to a policydb binary 
+ * representation file.
+ */
+static int mls_write_level(mls_level_t * l, struct policy_file *fp)
+{
+	uint32_t sens;
+	size_t items;
+
+	sens = cpu_to_le32(l->sens);
+	items = put_entry(&sens, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	if (ebitmap_write(&l->cat, fp))
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a MLS range structure to a policydb binary 
+ * representation file.
+ */
+static int mls_write_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+	uint32_t buf[3];
+	size_t items, items2;
+	int eq;
+
+	eq = mls_level_eq(&r->level[1], &r->level[0]);
+
+	items = 1;		/* item 0 is used for the item count */
+	buf[items++] = cpu_to_le32(r->level[0].sens);
+	if (!eq)
+		buf[items++] = cpu_to_le32(r->level[1].sens);
+	buf[0] = cpu_to_le32(items - 1);
+
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items2 != items)
+		return POLICYDB_ERROR;
+
+	if (ebitmap_write(&r->level[0].cat, fp))
+		return POLICYDB_ERROR;
+	if (!eq)
+		if (ebitmap_write(&r->level[1].cat, fp))
+			return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	level_datum_t *levdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+
+	levdatum = (level_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(levdatum->isalias);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (mls_write_level(levdatum->level, fp))
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	cat_datum_t *catdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+
+	catdatum = (cat_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(catdatum->s.value);
+	buf[items++] = cpu_to_le32(catdatum->isalias);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int role_trans_write(policydb_t *p, struct policy_file *fp)
+{
+	role_trans_t *r = p->role_tr;
+	role_trans_t *tr;
+	uint32_t buf[3];
+	size_t nel, items;
+	int new_roletr = (p->policy_type == POLICY_KERN &&
+			  p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+	int warning_issued = 0;
+
+	nel = 0;
+	for (tr = r; tr; tr = tr->next)
+		if(new_roletr || tr->tclass == SECCLASS_PROCESS)
+			nel++;
+
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (tr = r; tr; tr = tr->next) {
+		if (!new_roletr && tr->tclass != SECCLASS_PROCESS) {
+			if (!warning_issued)
+				WARN(fp->handle, "Discarding role_transition "
+				     "rules for security classes other than "
+				     "\"process\"");
+			warning_issued = 1;
+			continue;
+		}
+		buf[0] = cpu_to_le32(tr->role);
+		buf[1] = cpu_to_le32(tr->type);
+		buf[2] = cpu_to_le32(tr->new_role);
+		items = put_entry(buf, sizeof(uint32_t), 3, fp);
+		if (items != 3)
+			return POLICYDB_ERROR;
+		if (new_roletr) {
+			buf[0] = cpu_to_le32(tr->tclass);
+			items = put_entry(buf, sizeof(uint32_t), 1, fp);
+			if (items != 1)
+				return POLICYDB_ERROR;
+		}
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int role_allow_write(role_allow_t * r, struct policy_file *fp)
+{
+	role_allow_t *ra;
+	uint32_t buf[2];
+	size_t nel, items;
+
+	nel = 0;
+	for (ra = r; ra; ra = ra->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (ra = r; ra; ra = ra->next) {
+		buf[0] = cpu_to_le32(ra->role);
+		buf[1] = cpu_to_le32(ra->new_role);
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_write(filename_trans_t * r, struct policy_file *fp)
+{
+	filename_trans_t *ft;
+	uint32_t buf[4];
+	size_t nel, items, len;
+
+	nel = 0;
+	for (ft = r; ft; ft = ft->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (ft = r; ft; ft = ft->next) {
+		len = strlen(ft->name);
+		buf[0] = cpu_to_le32(len);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+
+		items = put_entry(ft->name, sizeof(char), len, fp);
+		if (items != len)
+			return POLICYDB_ERROR;
+
+		buf[0] = cpu_to_le32(ft->stype);
+		buf[1] = cpu_to_le32(ft->ttype);
+		buf[2] = cpu_to_le32(ft->tclass);
+		buf[3] = cpu_to_le32(ft->otype);
+		items = put_entry(buf, sizeof(uint32_t), 4, fp);
+		if (items != 4)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int role_set_write(role_set_t * x, struct policy_file *fp)
+{
+	size_t items;
+	uint32_t buf[1];
+
+	if (ebitmap_write(&x->roles, fp))
+		return POLICYDB_ERROR;
+
+	buf[0] = cpu_to_le32(x->flags);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int type_set_write(type_set_t * x, struct policy_file *fp)
+{
+	size_t items;
+	uint32_t buf[1];
+
+	if (ebitmap_write(&x->types, fp))
+		return POLICYDB_ERROR;
+	if (ebitmap_write(&x->negset, fp))
+		return POLICYDB_ERROR;
+
+	buf[0] = cpu_to_le32(x->flags);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	cond_bool_datum_t *booldatum;
+	uint32_t buf[3], len;
+	unsigned int items, items2;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	struct policydb *p = pd->p;
+
+	booldatum = (cond_bool_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(booldatum->s.value);
+	buf[items++] = cpu_to_le32(booldatum->state);
+	buf[items++] = cpu_to_le32(len);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+		buf[0] = cpu_to_le32(booldatum->flags);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+/*
+ * cond_write_cond_av_list doesn't write out the av_list nodes.
+ * Instead it writes out the key/value pairs from the avtab. This
+ * is necessary because there is no way to uniquely identifying rules
+ * in the avtab so it is not possible to associate individual rules
+ * in the avtab with a conditional without saving them as part of
+ * the conditional. This means that the avtab with the conditional
+ * rules will not be saved but will be rebuilt on policy load.
+ */
+static int cond_write_av_list(policydb_t * p,
+			      cond_av_list_t * list, struct policy_file *fp)
+{
+	uint32_t buf[4];
+	cond_av_list_t *cur_list, *new_list = NULL;
+	avtab_t expa;
+	uint32_t len, items;
+	unsigned int oldvers = (p->policy_type == POLICY_KERN
+				&& p->policyvers < POLICYDB_VERSION_AVTAB);
+	int rc = -1;
+
+	if (oldvers) {
+		if (avtab_init(&expa))
+			return POLICYDB_ERROR;
+		if (expand_cond_av_list(p, list, &new_list, &expa))
+			goto out;
+		list = new_list;
+	}
+
+	len = 0;
+	for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+		if (cur_list->node->parse_context)
+			len++;
+	}
+
+	buf[0] = cpu_to_le32(len);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		goto out;
+
+	if (len == 0) {
+		rc = 0;
+		goto out;
+	}
+
+	for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+		if (cur_list->node->parse_context)
+			if (avtab_write_item(p, cur_list->node, fp, 0, 1, NULL))
+				goto out;
+	}
+
+	rc = 0;
+      out:
+	if (oldvers) {
+		cond_av_list_destroy(new_list);
+		avtab_destroy(&expa);
+	}
+
+	return rc;
+}
+
+static int cond_write_node(policydb_t * p,
+			   cond_node_t * node, struct policy_file *fp)
+{
+	cond_expr_t *cur_expr;
+	uint32_t buf[2];
+	uint32_t items, items2, len;
+
+	buf[0] = cpu_to_le32(node->cur_state);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	/* expr */
+	len = 0;
+	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
+		len++;
+
+	buf[0] = cpu_to_le32(len);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
+		items = 0;
+		buf[items++] = cpu_to_le32(cur_expr->expr_type);
+		buf[items++] = cpu_to_le32(cur_expr->bool);
+		items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+		if (items2 != items)
+			return POLICYDB_ERROR;
+	}
+
+	if (p->policy_type == POLICY_KERN) {
+		if (cond_write_av_list(p, node->true_list, fp) != 0)
+			return POLICYDB_ERROR;
+		if (cond_write_av_list(p, node->false_list, fp) != 0)
+			return POLICYDB_ERROR;
+	} else {
+		if (avrule_write_list(node->avtrue_list, fp))
+			return POLICYDB_ERROR;
+		if (avrule_write_list(node->avfalse_list, fp))
+			return POLICYDB_ERROR;
+	}
+
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+		buf[0] = cpu_to_le32(node->flags);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int cond_write_list(policydb_t * p, cond_list_t * list,
+			   struct policy_file *fp)
+{
+	cond_node_t *cur;
+	uint32_t len, items;
+	uint32_t buf[1];
+
+	len = 0;
+	for (cur = list; cur != NULL; cur = cur->next)
+		len++;
+	buf[0] = cpu_to_le32(len);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	for (cur = list; cur != NULL; cur = cur->next) {
+		if (cond_write_node(p, cur, fp) != 0)
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a security context structure
+ * to a policydb binary representation file.
+ */
+static int context_write(struct policydb *p, context_struct_t * c,
+			 struct policy_file *fp)
+{
+	uint32_t buf[32];
+	size_t items, items2;
+
+	items = 0;
+	buf[items++] = cpu_to_le32(c->user);
+	buf[items++] = cpu_to_le32(c->role);
+	buf[items++] = cpu_to_le32(c->type);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items2 != items)
+		return POLICYDB_ERROR;
+	if ((p->policyvers >= POLICYDB_VERSION_MLS
+	     && p->policy_type == POLICY_KERN)
+	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policy_type == POLICY_BASE))
+		if (mls_write_range_helper(&c->range, fp))
+			return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+/*
+ * The following *_write functions are used to
+ * write the symbol data to a policy database
+ * binary representation file.
+ */
+
+static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	perm_datum_t *perdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+
+	perdatum = (perm_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(perdatum->s.value);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	common_datum_t *comdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+
+	comdatum = (common_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(comdatum->s.value);
+	buf[items++] = cpu_to_le32(comdatum->permissions.nprim);
+	buf[items++] = cpu_to_le32(comdatum->permissions.table->nel);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (hashtab_map(comdatum->permissions.table, perm_write, pd))
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int write_cons_helper(policydb_t * p,
+			     constraint_node_t * node, int allowxtarget,
+			     struct policy_file *fp)
+{
+	constraint_node_t *c;
+	constraint_expr_t *e;
+	uint32_t buf[3], nexpr;
+	int items;
+
+	for (c = node; c; c = c->next) {
+		nexpr = 0;
+		for (e = c->expr; e; e = e->next) {
+			nexpr++;
+		}
+		buf[0] = cpu_to_le32(c->permissions);
+		buf[1] = cpu_to_le32(nexpr);
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+		for (e = c->expr; e; e = e->next) {
+			items = 0;
+			buf[0] = cpu_to_le32(e->expr_type);
+			buf[1] = cpu_to_le32(e->attr);
+			buf[2] = cpu_to_le32(e->op);
+			items = put_entry(buf, sizeof(uint32_t), 3, fp);
+			if (items != 3)
+				return POLICYDB_ERROR;
+
+			switch (e->expr_type) {
+			case CEXPR_NAMES:
+				if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+					return POLICYDB_ERROR;
+				if (ebitmap_write(&e->names, fp)) {
+					return POLICYDB_ERROR;
+				}
+				if ((p->policy_type != POLICY_KERN &&
+						type_set_write(e->type_names, fp)) ||
+						(p->policy_type == POLICY_KERN &&
+						(p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) &&
+						type_set_write(e->type_names, fp))) {
+					return POLICYDB_ERROR;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	class_datum_t *cladatum;
+	constraint_node_t *c;
+	uint32_t buf[32], ncons;
+	size_t items, items2, len, len2;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	struct policydb *p = pd->p;
+
+	cladatum = (class_datum_t *) datum;
+
+	len = strlen(key);
+	if (cladatum->comkey)
+		len2 = strlen(cladatum->comkey);
+	else
+		len2 = 0;
+
+	ncons = 0;
+	for (c = cladatum->constraints; c; c = c->next) {
+		ncons++;
+	}
+
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(len2);
+	buf[items++] = cpu_to_le32(cladatum->s.value);
+	buf[items++] = cpu_to_le32(cladatum->permissions.nprim);
+	if (cladatum->permissions.table)
+		buf[items++] = cpu_to_le32(cladatum->permissions.table->nel);
+	else
+		buf[items++] = 0;
+	buf[items++] = cpu_to_le32(ncons);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (cladatum->comkey) {
+		items = put_entry(cladatum->comkey, 1, len2, fp);
+		if (items != len2)
+			return POLICYDB_ERROR;
+	}
+	if (hashtab_map(cladatum->permissions.table, perm_write, pd))
+		return POLICYDB_ERROR;
+
+	if (write_cons_helper(p, cladatum->constraints, 0, fp))
+		return POLICYDB_ERROR;
+
+	if ((p->policy_type == POLICY_KERN
+	     && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+	    || (p->policy_type == POLICY_BASE
+		&& p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+		/* write out the validatetrans rule */
+		ncons = 0;
+		for (c = cladatum->validatetrans; c; c = c->next) {
+			ncons++;
+		}
+		buf[0] = cpu_to_le32(ncons);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		if (write_cons_helper(p, cladatum->validatetrans, 1, fp))
+			return POLICYDB_ERROR;
+	}
+
+	if ((p->policy_type == POLICY_KERN &&
+	     p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) ||
+	    (p->policy_type == POLICY_BASE &&
+	     p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) {
+		buf[0] = cpu_to_le32(cladatum->default_user);
+		buf[1] = cpu_to_le32(cladatum->default_role);
+		buf[2] = cpu_to_le32(cladatum->default_range);
+		items = put_entry(buf, sizeof(uint32_t), 3, fp);
+		if (items != 3)
+			return POLICYDB_ERROR;
+	}
+
+	if ((p->policy_type == POLICY_KERN &&
+	     p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
+	    (p->policy_type == POLICY_BASE &&
+	     p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
+		buf[0] = cpu_to_le32(cladatum->default_type);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	role_datum_t *role;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	struct policydb *p = pd->p;
+
+	role = (role_datum_t *) datum;
+
+	/*
+	 * Role attributes are redundant for policy.X, skip them
+	 * when writing the roles symbol table. They are also skipped
+	 * when pp is downgraded.
+	 *
+	 * Their numbers would be deducted in policydb_write().
+	 */
+	if ((role->flavor == ROLE_ATTRIB) &&
+	    ((p->policy_type == POLICY_KERN) ||
+	     (p->policy_type != POLICY_KERN &&
+	      p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
+		return POLICYDB_SUCCESS;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(role->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(role->bounds);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (ebitmap_write(&role->dominates, fp))
+		return POLICYDB_ERROR;
+	if (p->policy_type == POLICY_KERN) {
+		if (ebitmap_write(&role->types.types, fp))
+			return POLICYDB_ERROR;
+	} else {
+		if (type_set_write(&role->types, fp))
+			return POLICYDB_ERROR;
+	}
+
+	if (p->policy_type != POLICY_KERN &&
+	    p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+		buf[0] = cpu_to_le32(role->flavor);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+
+		if (ebitmap_write(&role->roles, fp))
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	type_datum_t *typdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	struct policydb *p = pd->p;
+
+	typdatum = (type_datum_t *) datum;
+
+	/*
+	 * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
+	 * does not support to load entries of attribute, so we skip to write it.
+	 */
+	if (p->policy_type == POLICY_KERN
+	    && p->policyvers < POLICYDB_VERSION_BOUNDARY
+	    && typdatum->flavor == TYPE_ATTRIB)
+		return POLICYDB_SUCCESS;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(typdatum->s.value);
+	if (policydb_has_boundary_feature(p)) {
+		uint32_t properties = 0;
+
+		if (p->policy_type != POLICY_KERN
+		    && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+			buf[items++] = cpu_to_le32(typdatum->primary);
+		}
+
+		if (typdatum->primary)
+			properties |= TYPEDATUM_PROPERTY_PRIMARY;
+
+		if (typdatum->flavor == TYPE_ATTRIB) {
+			properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+		} else if (typdatum->flavor == TYPE_ALIAS
+			   && p->policy_type != POLICY_KERN)
+			properties |= TYPEDATUM_PROPERTY_ALIAS;
+
+		if (typdatum->flags & TYPE_FLAGS_PERMISSIVE
+		    && p->policy_type != POLICY_KERN)
+			properties |= TYPEDATUM_PROPERTY_PERMISSIVE;
+
+		buf[items++] = cpu_to_le32(properties);
+		buf[items++] = cpu_to_le32(typdatum->bounds);
+	} else {
+		buf[items++] = cpu_to_le32(typdatum->primary);
+
+		if (p->policy_type != POLICY_KERN) {
+			buf[items++] = cpu_to_le32(typdatum->flavor);
+
+			if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+				buf[items++] = cpu_to_le32(typdatum->flags);
+			else if (typdatum->flags & TYPE_FLAGS_PERMISSIVE)
+				WARN(fp->handle, "Warning! Module policy "
+				     "version %d cannot support permissive "
+				     "types, but one was defined",
+				     p->policyvers);
+		}
+	}
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	if (p->policy_type != POLICY_KERN) {
+		if (ebitmap_write(&typdatum->types, fp))
+			return POLICYDB_ERROR;
+	}
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	return POLICYDB_SUCCESS;
+}
+
+static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	user_datum_t *usrdatum;
+	uint32_t buf[32];
+	size_t items, items2, len;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	struct policydb *p = pd->p;
+
+	usrdatum = (user_datum_t *) datum;
+
+	len = strlen(key);
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	buf[items++] = cpu_to_le32(usrdatum->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(usrdatum->bounds);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	items = put_entry(key, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	if (p->policy_type == POLICY_KERN) {
+		if (ebitmap_write(&usrdatum->roles.roles, fp))
+			return POLICYDB_ERROR;
+	} else {
+		if (role_set_write(&usrdatum->roles, fp))
+			return POLICYDB_ERROR;
+	}
+
+	if ((p->policyvers >= POLICYDB_VERSION_MLS
+	     && p->policy_type == POLICY_KERN)
+	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+		&& p->policy_type == POLICY_MOD)
+	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+		&& p->policy_type == POLICY_BASE)) {
+		if (mls_write_range_helper(&usrdatum->exp_range, fp))
+			return POLICYDB_ERROR;
+		if (mls_write_level(&usrdatum->exp_dfltlevel, fp))
+			return POLICYDB_ERROR;
+	} else if ((p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+		    && p->policy_type == POLICY_MOD)
+		   || (p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+		       && p->policy_type == POLICY_BASE)) {
+		if (mls_write_semantic_range_helper(&usrdatum->range, fp))
+			return -1;
+		if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp))
+			return -1;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+				void *datap) = {
+common_write, class_write, role_write, type_write, user_write,
+	    cond_write_bool, sens_write, cat_write,};
+
+static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p,
+			  struct policy_file *fp)
+{
+	unsigned int i, j;
+	size_t nel, items, len;
+	uint32_t buf[32];
+	ocontext_t *c;
+	for (i = 0; i < info->ocon_num; i++) {
+		nel = 0;
+		for (c = p->ocontexts[i]; c; c = c->next)
+			nel++;
+		buf[0] = cpu_to_le32(nel);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		for (c = p->ocontexts[i]; c; c = c->next) {
+			switch (i) {
+			case OCON_XEN_ISID:
+				buf[0] = cpu_to_le32(c->sid[0]);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_XEN_PIRQ:
+				buf[0] = cpu_to_le32(c->u.pirq);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_XEN_IOPORT:
+				buf[0] = c->u.ioport.low_ioport;
+				buf[1] = c->u.ioport.high_ioport;
+				for (j = 0; j < 2; j++)
+					buf[j] = cpu_to_le32(buf[j]);
+				items = put_entry(buf, sizeof(uint32_t), 2, fp);
+				if (items != 2)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_XEN_IOMEM:
+				if (p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE) {
+					uint64_t b64[2];
+					b64[0] = c->u.iomem.low_iomem;
+					b64[1] = c->u.iomem.high_iomem;
+					for (j = 0; j < 2; j++)
+						b64[j] = cpu_to_le64(b64[j]);
+					items = put_entry(b64, sizeof(uint64_t), 2, fp);
+					if (items != 2)
+						return POLICYDB_ERROR;
+				} else {
+					if (c->u.iomem.high_iomem > 0xFFFFFFFFULL) {
+						ERR(fp->handle, "policy version %d"
+							" cannot represent IOMEM addresses over 16TB",
+							p->policyvers);
+						return POLICYDB_ERROR;
+					}
+
+					buf[0] = c->u.iomem.low_iomem;
+					buf[1] = c->u.iomem.high_iomem;
+					for (j = 0; j < 2; j++)
+						buf[j] = cpu_to_le32(buf[j]);
+					items = put_entry(buf, sizeof(uint32_t), 2, fp);
+					if (items != 2)
+						return POLICYDB_ERROR;
+				}
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_XEN_PCIDEVICE:
+				buf[0] = cpu_to_le32(c->u.device);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_XEN_DEVICETREE:
+				len = strlen(c->u.name);
+				buf[0] = cpu_to_le32(len);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				items = put_entry(c->u.name, 1, len, fp);
+				if (items != len)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			}
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write_selinux(struct policydb_compat_info *info,
+	policydb_t *p, struct policy_file *fp)
+{
+	unsigned int i, j;
+	size_t nel, items, len;
+	uint32_t buf[32];
+	ocontext_t *c;
+	for (i = 0; i < info->ocon_num; i++) {
+		nel = 0;
+		for (c = p->ocontexts[i]; c; c = c->next)
+			nel++;
+		buf[0] = cpu_to_le32(nel);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		for (c = p->ocontexts[i]; c; c = c->next) {
+			switch (i) {
+			case OCON_ISID:
+				buf[0] = cpu_to_le32(c->sid[0]);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_FS:
+			case OCON_NETIF:
+				len = strlen(c->u.name);
+				buf[0] = cpu_to_le32(len);
+				items = put_entry(buf, sizeof(uint32_t), 1, fp);
+				if (items != 1)
+					return POLICYDB_ERROR;
+				items = put_entry(c->u.name, 1, len, fp);
+				if (items != len)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[1], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_PORT:
+				buf[0] = c->u.port.protocol;
+				buf[1] = c->u.port.low_port;
+				buf[2] = c->u.port.high_port;
+				for (j = 0; j < 3; j++) {
+					buf[j] = cpu_to_le32(buf[j]);
+				}
+				items = put_entry(buf, sizeof(uint32_t), 3, fp);
+				if (items != 3)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_NODE:
+				buf[0] = c->u.node.addr; /* network order */
+				buf[1] = c->u.node.mask; /* network order */
+				items = put_entry(buf, sizeof(uint32_t), 2, fp);
+				if (items != 2)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_FSUSE:
+				buf[0] = cpu_to_le32(c->v.behavior);
+				len = strlen(c->u.name);
+				buf[1] = cpu_to_le32(len);
+				items = put_entry(buf, sizeof(uint32_t), 2, fp);
+				if (items != 2)
+					return POLICYDB_ERROR;
+				items = put_entry(c->u.name, 1, len, fp);
+				if (items != len)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			case OCON_NODE6:
+				for (j = 0; j < 4; j++)
+					buf[j] = c->u.node6.addr[j]; /* network order */
+				for (j = 0; j < 4; j++)
+					buf[j + 4] = c->u.node6.mask[j]; /* network order */
+				items = put_entry(buf, sizeof(uint32_t), 8, fp);
+				if (items != 8)
+					return POLICYDB_ERROR;
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
+			}
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write(struct policydb_compat_info *info, policydb_t * p,
+	struct policy_file *fp)
+{
+	int rc = POLICYDB_ERROR;
+	switch (p->target_platform) {
+	case SEPOL_TARGET_SELINUX:
+		rc = ocontext_write_selinux(info, p, fp);
+		break;
+	case SEPOL_TARGET_XEN:
+		rc = ocontext_write_xen(info, p, fp);
+		break;
+	}
+	return rc;
+}
+
+static int genfs_write(policydb_t * p, struct policy_file *fp)
+{
+	genfs_t *genfs;
+	ocontext_t *c;
+	size_t nel = 0, items, len;
+	uint32_t buf[32];
+
+	for (genfs = p->genfs; genfs; genfs = genfs->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (genfs = p->genfs; genfs; genfs = genfs->next) {
+		len = strlen(genfs->fstype);
+		buf[0] = cpu_to_le32(len);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		items = put_entry(genfs->fstype, 1, len, fp);
+		if (items != len)
+			return POLICYDB_ERROR;
+		nel = 0;
+		for (c = genfs->head; c; c = c->next)
+			nel++;
+		buf[0] = cpu_to_le32(nel);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		for (c = genfs->head; c; c = c->next) {
+			len = strlen(c->u.name);
+			buf[0] = cpu_to_le32(len);
+			items = put_entry(buf, sizeof(uint32_t), 1, fp);
+			if (items != 1)
+				return POLICYDB_ERROR;
+			items = put_entry(c->u.name, 1, len, fp);
+			if (items != len)
+				return POLICYDB_ERROR;
+			buf[0] = cpu_to_le32(c->v.sclass);
+			items = put_entry(buf, sizeof(uint32_t), 1, fp);
+			if (items != 1)
+				return POLICYDB_ERROR;
+			if (context_write(p, &c->context[0], fp))
+				return POLICYDB_ERROR;
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int range_write(policydb_t * p, struct policy_file *fp)
+{
+	size_t nel, items;
+	struct range_trans *rt;
+	uint32_t buf[2];
+	int new_rangetr = (p->policy_type == POLICY_KERN &&
+			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+	int warning_issued = 0;
+
+	nel = 0;
+	for (rt = p->range_tr; rt; rt = rt->next) {
+		/* all range_transitions are written for the new format, only
+		   process related range_transitions are written for the old
+		   format, so count accordingly */
+		if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
+			nel++;
+	}
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (rt = p->range_tr; rt; rt = rt->next) {
+		if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
+			if (!warning_issued)
+				WARN(fp->handle, "Discarding range_transition "
+				     "rules for security classes other than "
+				     "\"process\"");
+			warning_issued = 1;
+			continue;
+		}
+		buf[0] = cpu_to_le32(rt->source_type);
+		buf[1] = cpu_to_le32(rt->target_type);
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+		if (new_rangetr) {
+			buf[0] = cpu_to_le32(rt->target_class);
+			items = put_entry(buf, sizeof(uint32_t), 1, fp);
+			if (items != 1)
+				return POLICYDB_ERROR;
+		}
+		if (mls_write_range_helper(&rt->target_range, fp))
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+/************** module writing functions below **************/
+
+static int avrule_write(avrule_t * avrule, struct policy_file *fp)
+{
+	size_t items, items2;
+	uint32_t buf[32], len;
+	class_perm_node_t *cur;
+
+	if (avrule->specified & AVRULE_XPERMS) {
+		ERR(fp->handle, "module policy does not support extended"
+				" permissions rules and one was specified");
+		return POLICYDB_ERROR;
+	}
+
+	items = 0;
+	buf[items++] = cpu_to_le32(avrule->specified);
+	buf[items++] = cpu_to_le32(avrule->flags);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items2 != items)
+		return POLICYDB_ERROR;
+
+	if (type_set_write(&avrule->stypes, fp))
+		return POLICYDB_ERROR;
+
+	if (type_set_write(&avrule->ttypes, fp))
+		return POLICYDB_ERROR;
+
+	cur = avrule->perms;
+	len = 0;
+	while (cur) {
+		len++;
+		cur = cur->next;
+	}
+	items = 0;
+	buf[items++] = cpu_to_le32(len);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items2 != items)
+		return POLICYDB_ERROR;
+	cur = avrule->perms;
+	while (cur) {
+		items = 0;
+		buf[items++] = cpu_to_le32(cur->tclass);
+		buf[items++] = cpu_to_le32(cur->data);
+		items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+		if (items2 != items)
+			return POLICYDB_ERROR;
+
+		cur = cur->next;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp)
+{
+	uint32_t buf[32], len;
+	avrule_t *avrule;
+
+	avrule = avrules;
+	len = 0;
+	while (avrule) {
+		len++;
+		avrule = avrule->next;
+	}
+
+	buf[0] = cpu_to_le32(len);
+	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1)
+		return POLICYDB_ERROR;
+
+	avrule = avrules;
+	while (avrule) {
+		if (avrule_write(avrule, fp))
+			return POLICYDB_ERROR;
+		avrule = avrule->next;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
+static int only_process(ebitmap_t *in)
+{
+	unsigned int i;
+	ebitmap_node_t *node;
+
+	ebitmap_for_each_bit(in, node, i) {
+		if (ebitmap_node_get_bit(node, i) &&
+		    i != SECCLASS_PROCESS - 1)
+			return 0;
+	}
+	return 1;
+}
+
+static int role_trans_rule_write(policydb_t *p, role_trans_rule_t * t,
+				 struct policy_file *fp)
+{
+	int nel = 0;
+	size_t items;
+	uint32_t buf[1];
+	role_trans_rule_t *tr;
+	int warned = 0;
+	int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS;
+
+	for (tr = t; tr; tr = tr->next)
+		if (new_role || only_process(&tr->classes))
+			nel++;
+
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (tr = t; tr; tr = tr->next) {
+		if (!new_role && !only_process(&tr->classes)) {
+			if (!warned)
+				WARN(fp->handle, "Discarding role_transition "
+					"rules for security classes other than "
+					"\"process\"");
+			warned = 1;
+			continue;
+		}
+		if (role_set_write(&tr->roles, fp))
+			return POLICYDB_ERROR;
+		if (type_set_write(&tr->types, fp))
+			return POLICYDB_ERROR;
+		if (new_role)
+			if (ebitmap_write(&tr->classes, fp))
+				return POLICYDB_ERROR;
+		buf[0] = cpu_to_le32(tr->new_role);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp)
+{
+	int nel = 0;
+	size_t items;
+	uint32_t buf[1];
+	role_allow_rule_t *ra;
+
+	for (ra = r; ra; ra = ra->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (ra = r; ra; ra = ra->next) {
+		if (role_set_write(&ra->roles, fp))
+			return POLICYDB_ERROR;
+		if (role_set_write(&ra->new_roles, fp))
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_file *fp)
+{
+	int nel = 0;
+	size_t items;
+	uint32_t buf[2], len;
+	filename_trans_rule_t *ftr;
+
+	for (ftr = t; ftr; ftr = ftr->next)
+		nel++;
+
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	for (ftr = t; ftr; ftr = ftr->next) {
+		len = strlen(ftr->name);
+		buf[0] = cpu_to_le32(len);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+
+		items = put_entry(ftr->name, sizeof(char), len, fp);
+		if (items != len)
+			return POLICYDB_ERROR;
+
+		if (type_set_write(&ftr->stypes, fp))
+			return POLICYDB_ERROR;
+		if (type_set_write(&ftr->ttypes, fp))
+			return POLICYDB_ERROR;
+
+		buf[0] = cpu_to_le32(ftr->tclass);
+		buf[1] = cpu_to_le32(ftr->otype);
+
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int range_trans_rule_write(range_trans_rule_t * t,
+				  struct policy_file *fp)
+{
+	int nel = 0;
+	size_t items;
+	uint32_t buf[1];
+	range_trans_rule_t *rt;
+
+	for (rt = t; rt; rt = rt->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (rt = t; rt; rt = rt->next) {
+		if (type_set_write(&rt->stypes, fp))
+			return POLICYDB_ERROR;
+		if (type_set_write(&rt->ttypes, fp))
+			return POLICYDB_ERROR;
+		if (ebitmap_write(&rt->tclasses, fp))
+			return POLICYDB_ERROR;
+		if (mls_write_semantic_range_helper(&rt->trange, fp))
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int scope_index_write(scope_index_t * scope_index,
+			     unsigned int num_scope_syms,
+			     struct policy_file *fp)
+{
+	unsigned int i;
+	uint32_t buf[1];
+	for (i = 0; i < num_scope_syms; i++) {
+		if (ebitmap_write(scope_index->scope + i, fp) == -1) {
+			return POLICYDB_ERROR;
+		}
+	}
+	buf[0] = cpu_to_le32(scope_index->class_perms_len);
+	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+		return POLICYDB_ERROR;
+	}
+	for (i = 0; i < scope_index->class_perms_len; i++) {
+		if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) {
+			return POLICYDB_ERROR;
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms,
+			     policydb_t * p, struct policy_file *fp)
+{
+	struct policy_data pd;
+	uint32_t buf[2];
+	int i;
+	buf[0] = cpu_to_le32(decl->decl_id);
+	buf[1] = cpu_to_le32(decl->enabled);
+	if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+		return POLICYDB_ERROR;
+	}
+	if (cond_write_list(p, decl->cond_list, fp) == -1 ||
+	    avrule_write_list(decl->avrules, fp) == -1 ||
+	    role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 ||
+	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
+		return POLICYDB_ERROR;
+	}
+
+	if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+	    filename_trans_rule_write(decl->filename_trans_rules, fp))
+		return POLICYDB_ERROR;
+
+	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
+		return POLICYDB_ERROR;
+	}
+	if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 ||
+	    scope_index_write(&decl->declared, num_scope_syms, fp) == -1) {
+		return POLICYDB_ERROR;
+	}
+	pd.fp = fp;
+	pd.p = p;
+	for (i = 0; i < num_scope_syms; i++) {
+		buf[0] = cpu_to_le32(decl->symtab[i].nprim);
+		buf[1] = cpu_to_le32(decl->symtab[i].table->nel);
+		if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+			return POLICYDB_ERROR;
+		}
+		if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) {
+			return POLICYDB_ERROR;
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int avrule_block_write(avrule_block_t * block, int num_scope_syms,
+			      policydb_t * p, struct policy_file *fp)
+{
+	/* first write a count of the total number of blocks */
+	uint32_t buf[1], num_blocks = 0;
+	avrule_block_t *cur;
+	for (cur = block; cur != NULL; cur = cur->next) {
+		num_blocks++;
+	}
+	buf[0] = cpu_to_le32(num_blocks);
+	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+		return POLICYDB_ERROR;
+	}
+
+	/* now write each block */
+	for (cur = block; cur != NULL; cur = cur->next) {
+		uint32_t num_decls = 0;
+		avrule_decl_t *decl;
+		/* write a count of number of branches */
+		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+			num_decls++;
+		}
+		buf[0] = cpu_to_le32(num_decls);
+		if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+			return POLICYDB_ERROR;
+		}
+		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+			if (avrule_decl_write(decl, num_scope_syms, p, fp) ==
+			    -1) {
+				return POLICYDB_ERROR;
+			}
+		}
+	}
+	return POLICYDB_SUCCESS;
+}
+
+static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+	scope_datum_t *scope = (scope_datum_t *) datum;
+	struct policy_data *pd = ptr;
+	struct policy_file *fp = pd->fp;
+	uint32_t static_buf[32], *dyn_buf = NULL, *buf;
+	size_t key_len = strlen(key);
+	unsigned int items = 2 + scope->decl_ids_len, i;
+	int rc;
+
+	buf = static_buf;
+	if (items >= (sizeof(static_buf) / 4)) {
+		/* too many things required, so dynamically create a
+		 * buffer.  this would have been easier with C99's
+		 * dynamic arrays... */
+		rc = POLICYDB_ERROR;
+		dyn_buf = malloc(items * sizeof(*dyn_buf));
+		if (!dyn_buf)
+			goto err;
+		buf = dyn_buf;
+	}
+	buf[0] = cpu_to_le32(key_len);
+
+	rc = POLICYDB_ERROR;
+	if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
+	    put_entry(key, 1, key_len, fp) != key_len)
+		goto err;
+	buf[0] = cpu_to_le32(scope->scope);
+	buf[1] = cpu_to_le32(scope->decl_ids_len);
+
+	for (i = 0; i < scope->decl_ids_len; i++)
+		buf[2 + i] = cpu_to_le32(scope->decl_ids[i]);
+
+	rc = POLICYDB_ERROR;
+	if (put_entry(buf, sizeof(*buf), items, fp) != items)
+		goto err;
+	rc = POLICYDB_SUCCESS;
+err:
+	free(dyn_buf);
+	return rc;
+}
+
+static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
+			     hashtab_datum_t datum, void *args)
+{
+	type_datum_t *typdatum = datum;
+	uint32_t *p_nel = args;
+
+	if (typdatum->flavor == TYPE_ATTRIB) {
+		/* uncount attribute from total number of types */
+		(*p_nel)--;
+	}
+	return 0;
+}
+
+static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
+			     hashtab_datum_t datum, void *args)
+{
+	role_datum_t *role = datum;
+	uint32_t *p_nel = args;
+
+	if (role->flavor == ROLE_ATTRIB) {
+		/* uncount attribute from total number of roles */
+		(*p_nel)--;
+	}
+	return 0;
+}
+
+/*
+ * Write the configuration data in a policy database
+ * structure to a policy database binary representation
+ * file.
+ */
+int policydb_write(policydb_t * p, struct policy_file *fp)
+{
+	unsigned int i, num_syms;
+	uint32_t buf[32], config;
+	size_t items, items2, len;
+	struct policydb_compat_info *info;
+	struct policy_data pd;
+	const char *policydb_str;
+
+	if (p->unsupported_format)
+		return POLICYDB_UNSUPPORTED;
+
+	pd.fp = fp;
+	pd.p = p;
+
+	config = 0;
+	if (p->mls) {
+		if ((p->policyvers < POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_KERN) ||
+		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_BASE) ||
+		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+		    p->policy_type == POLICY_MOD)) {
+			ERR(fp->handle, "policy version %d cannot support MLS",
+			    p->policyvers);
+			return POLICYDB_ERROR;
+		}
+		config |= POLICYDB_CONFIG_MLS;
+	}
+
+	config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown);
+
+	/* Write the magic number and string identifiers. */
+	items = 0;
+	if (p->policy_type == POLICY_KERN) {
+		buf[items++] = cpu_to_le32(POLICYDB_MAGIC);
+		len = strlen(policydb_target_strings[p->target_platform]);
+		policydb_str = policydb_target_strings[p->target_platform];
+	} else {
+		buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC);
+		len = strlen(POLICYDB_MOD_STRING);
+		policydb_str = POLICYDB_MOD_STRING;
+	}
+	buf[items++] = cpu_to_le32(len);
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+	items = put_entry(policydb_str, 1, len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
+
+	/* Write the version, config, and table sizes. */
+	items = 0;
+	info = policydb_lookup_compat(p->policyvers, p->policy_type,
+					p->target_platform);
+	if (!info) {
+		ERR(fp->handle, "compatibility lookup failed for policy "
+		    "version %d", p->policyvers);
+		return POLICYDB_ERROR;
+	}
+
+	if (p->policy_type != POLICY_KERN) {
+		buf[items++] = cpu_to_le32(p->policy_type);
+	}
+	buf[items++] = cpu_to_le32(p->policyvers);
+	buf[items++] = cpu_to_le32(config);
+	buf[items++] = cpu_to_le32(info->sym_num);
+	buf[items++] = cpu_to_le32(info->ocon_num);
+
+	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+	if (items != items2)
+		return POLICYDB_ERROR;
+
+	if (p->policy_type == POLICY_MOD) {
+		/* Write module name and version */
+		len = strlen(p->name);
+		buf[0] = cpu_to_le32(len);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		items = put_entry(p->name, 1, len, fp);
+		if (items != len)
+			return POLICYDB_ERROR;
+		len = strlen(p->version);
+		buf[0] = cpu_to_le32(len);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		items = put_entry(p->version, 1, len, fp);
+		if (items != len)
+			return POLICYDB_ERROR;
+	}
+
+	if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_KERN) ||
+	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_BASE) ||
+	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+	     p->policy_type == POLICY_MOD)) {
+		if (ebitmap_write(&p->policycaps, fp) == -1)
+			return POLICYDB_ERROR;
+	}
+
+	if (p->policyvers < POLICYDB_VERSION_PERMISSIVE &&
+	    p->policy_type == POLICY_KERN) {
+		ebitmap_node_t *tnode;
+
+		ebitmap_for_each_bit(&p->permissive_map, tnode, i) {
+			if (ebitmap_node_get_bit(tnode, i)) {
+				WARN(fp->handle, "Warning! Policy version %d cannot "
+				     "support permissive types, but some were defined",
+				     p->policyvers);
+				break;
+			}
+		}
+	}
+
+	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+	    p->policy_type == POLICY_KERN) {
+		if (ebitmap_write(&p->permissive_map, fp) == -1)
+			return POLICYDB_ERROR;
+	}
+
+	num_syms = info->sym_num;
+	for (i = 0; i < num_syms; i++) {
+		buf[0] = cpu_to_le32(p->symtab[i].nprim);
+		buf[1] = p->symtab[i].table->nel;
+
+		/*
+		 * A special case when writing type/attribute symbol table.
+		 * The kernel policy version less than 24 does not support
+		 * to load entries of attribute, so we have to re-calculate
+		 * the actual number of types except for attributes.
+		 */
+		if (i == SYM_TYPES &&
+		    p->policyvers < POLICYDB_VERSION_BOUNDARY &&
+		    p->policy_type == POLICY_KERN) {
+			hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]);
+		}
+
+		/*
+		 * Another special case when writing role/attribute symbol
+		 * table, role attributes are redundant for policy.X, or
+		 * when the pp's version is not big enough. So deduct
+		 * their numbers from p_roles.table->nel.
+		 */
+		if ((i == SYM_ROLES) &&
+		    ((p->policy_type == POLICY_KERN) ||
+		     (p->policy_type != POLICY_KERN &&
+		      p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
+			(void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]);
+
+		buf[1] = cpu_to_le32(buf[1]);
+		items = put_entry(buf, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return POLICYDB_ERROR;
+		if (hashtab_map(p->symtab[i].table, write_f[i], &pd))
+			return POLICYDB_ERROR;
+	}
+
+	if (p->policy_type == POLICY_KERN) {
+		if (avtab_write(p, &p->te_avtab, fp))
+			return POLICYDB_ERROR;
+		if (p->policyvers < POLICYDB_VERSION_BOOL) {
+			if (p->p_bools.nprim)
+				WARN(fp->handle, "Discarding "
+				     "booleans and conditional rules");
+		} else {
+			if (cond_write_list(p, p->cond_list, fp))
+				return POLICYDB_ERROR;
+		}
+		if (role_trans_write(p, fp))
+			return POLICYDB_ERROR;
+		if (role_allow_write(p->role_allow, fp))
+			return POLICYDB_ERROR;
+		if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
+			if (filename_trans_write(p->filename_trans, fp))
+				return POLICYDB_ERROR;
+		} else {
+			if (p->filename_trans)
+				WARN(fp->handle, "Discarding filename type transition rules");
+		}
+	} else {
+		if (avrule_block_write(p->global, num_syms, p, fp) == -1) {
+			return POLICYDB_ERROR;
+		}
+
+		for (i = 0; i < num_syms; i++) {
+			buf[0] = cpu_to_le32(p->scope[i].table->nel);
+			if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+				return POLICYDB_ERROR;
+			}
+			if (hashtab_map(p->scope[i].table, scope_write, &pd))
+				return POLICYDB_ERROR;
+		}
+	}
+
+	if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) {
+		return POLICYDB_ERROR;
+	}
+
+	if ((p->policyvers >= POLICYDB_VERSION_MLS
+	     && p->policy_type == POLICY_KERN)
+	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+		&& p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS
+		&& p->policy_type == POLICY_BASE)) {
+		if (range_write(p, fp)) {
+			return POLICYDB_ERROR;
+		}
+	}
+
+	if (p->policy_type == POLICY_KERN
+	    && p->policyvers >= POLICYDB_VERSION_AVTAB) {
+		for (i = 0; i < p->p_types.nprim; i++) {
+			if (ebitmap_write(&p->type_attr_map[i], fp) == -1)
+				return POLICYDB_ERROR;
+		}
+	}
+
+	return POLICYDB_SUCCESS;
+}
diff --git a/libsepol/tests/Makefile b/libsepol/tests/Makefile
new file mode 100644
index 0000000..dd7bd33
--- /dev/null
+++ b/libsepol/tests/Makefile
@@ -0,0 +1,54 @@
+M4 ?= m4
+MKDIR ?= mkdir
+EXE ?= libsepol-tests
+
+CFLAGS += -g3 -gdwarf-2 -o0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter -Werror
+
+# Statically link libsepol on the assumption that we are going to
+# be testing internal functions.
+LIBSEPOL := ../src/libsepol.a
+
+# In order to load source policies we need to link in the checkpolicy/checkmodule parser and util code.
+# This is less than ideal, but it makes the tests easier to maintain by allowing source policies
+# to be loaded directly.
+CHECKPOLICY := ../../checkpolicy/
+CPPFLAGS += -I../include/ -I$(CHECKPOLICY)
+
+# test program object files
+objs := $(patsubst %.c,%.o,$(wildcard *.c))
+parserobjs := $(CHECKPOLICY)queue.o $(CHECKPOLICY)y.tab.o \
+	$(CHECKPOLICY)parse_util.o $(CHECKPOLICY)lex.yy.o \
+	$(CHECKPOLICY)policy_define.o $(CHECKPOLICY)module_compiler.o
+
+# test policy pieces
+m4support := $(wildcard policies/support/*.spt)
+testsuites := $(wildcard policies/test-*)
+policysrc := $(foreach path,$(testsuites),$(wildcard $(path)/*.conf))
+stdpol := $(addsuffix .std,$(policysrc))
+mlspol := $(addsuffix .mls,$(policysrc))
+policies := $(stdpol) $(mlspol)
+
+all: $(EXE) $(policies)
+policies: $(policies)
+
+$(EXE): $(objs) $(parserobjs) $(LIBSEPOL)
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(objs) $(parserobjs) -lfl -lcunit -lcurses $(LIBSEPOL) -o $@
+
+%.conf.std: $(m4support) %.conf
+	$(M4) $(M4PARAMS) $^ > $@
+
+%.conf.mls: $(m4support) %.conf
+	$(M4) $(M4PARAMS) -D enable_mls $^ > $@
+
+clean: 
+	rm -f $(objs) $(EXE)
+	rm -f $(policies)
+	rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo
+	
+
+test: $(EXE) $(policies)
+	$(MKDIR) -p policies/test-downgrade
+	../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi	
+	./$(EXE)
+
+.PHONY: all policies clean test
diff --git a/libsepol/tests/debug.c b/libsepol/tests/debug.c
new file mode 100644
index 0000000..90aa6e0
--- /dev/null
+++ b/libsepol/tests/debug.c
@@ -0,0 +1,69 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include "debug.h"
+
+#include <stdlib.h>
+
+void print_ebitmap(ebitmap_t * bitmap, FILE * fp)
+{
+	uint32_t i;
+	for (i = 0; i < bitmap->highbit; i++) {
+		fprintf(fp, "%d", ebitmap_get_bit(bitmap, i));
+	}
+	fprintf(fp, "\n");
+}
+
+/* stolen from dispol.c */
+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! (%d)", cur->expr_type);
+			break;
+		}
+	}
+}
diff --git a/libsepol/tests/debug.h b/libsepol/tests/debug.h
new file mode 100644
index 0000000..c25ebd4
--- /dev/null
+++ b/libsepol/tests/debug.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+extern void print_ebitmap(ebitmap_t * bitmap, FILE * fp);
+extern void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp);
diff --git a/libsepol/tests/helpers.c b/libsepol/tests/helpers.c
new file mode 100644
index 0000000..542e467
--- /dev/null
+++ b/libsepol/tests/helpers.c
@@ -0,0 +1,81 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *         Chad Sellers <csellers@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
+ */
+
+/* This has helper functions that are common between tests */
+
+#include "helpers.h"
+#include "parse_util.h"
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+#include <stdlib.h>
+#include <limits.h>
+
+int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name)
+{
+	char filename[PATH_MAX];
+
+	if (mls) {
+		if (snprintf(filename, PATH_MAX, "policies/%s/%s.mls", test_name, policy_name) < 0) {
+			return -1;
+		}
+	} else {
+		if (snprintf(filename, PATH_MAX, "policies/%s/%s.std", test_name, policy_name) < 0) {
+			return -1;
+		}
+	}
+
+	if (policydb_init(p)) {
+		fprintf(stderr, "Out of memory");
+		return -1;
+	}
+
+	p->policy_type = policy_type;
+	p->mls = mls;
+
+	if (read_source_policy(p, filename, test_name)) {
+		fprintf(stderr, "failed to read policy %s\n", filename);
+		policydb_destroy(p);
+		return -1;
+	}
+
+	return 0;
+}
+
+avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym)
+{
+	scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symtab].table, sym);
+
+	if (scope == NULL) {
+		return NULL;
+	}
+	if (scope->scope != SCOPE_DECL) {
+		return NULL;
+	}
+	if (scope->decl_ids_len != 1) {
+		return NULL;
+	}
+
+	return p->decl_val_to_struct[scope->decl_ids[0] - 1];
+}
diff --git a/libsepol/tests/helpers.h b/libsepol/tests/helpers.h
new file mode 100644
index 0000000..418ee95
--- /dev/null
+++ b/libsepol/tests/helpers.h
@@ -0,0 +1,59 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *         Chad Sellers <csellers@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
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+/* helper functions */
+
+/* Load a source policy into p. policydb_init will called within this function.
+ * 
+ * Example: test_load_policy(p, POLICY_BASE, 1, "foo", "base.conf") will load the
+ *  policy "policies/foo/mls/base.conf" into p.
+ *
+ * Arguments:
+ *  p            policydb_t into which the policy will be read. This should be
+ *                malloc'd but not passed to policydb_init.
+ *  policy_type  Type of policy expected - POLICY_BASE or POLICY_MOD.
+ *  mls          Boolean value indicating whether an mls policy is expected.
+ *  test_name    Name of the test which will be the name of the directory in
+ *                which the policies are stored.
+ *  policy_name  Name of the policy in the directory.
+ *
+ * Returns:
+ *  0            success
+ * -1            error - the policydb will be destroyed but not freed.
+ */
+extern int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name);
+
+/* Find an avrule_decl_t by a unique symbol. If the symbol is declared in more
+ * than one decl an error is returned.
+ *
+ * Returns:
+ *  decl      success 
+ *  NULL      error (including more than one declaration)
+ */
+extern avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym);
+
+#endif
diff --git a/libsepol/tests/libsepol-tests.c b/libsepol/tests/libsepol-tests.c
new file mode 100644
index 0000000..9302f72
--- /dev/null
+++ b/libsepol/tests/libsepol-tests.c
@@ -0,0 +1,118 @@
+/*
+ * 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 "test-cond.h"
+#include "test-linker.h"
+#include "test-expander.h"
+#include "test-deps.h"
+#include "test-downgrade.h"
+
+#include <CUnit/Basic.h>
+#include <CUnit/Console.h>
+#include <CUnit/TestDB.h>
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+int mls;
+
+#define DECLARE_SUITE(name) \
+	suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \
+	if (NULL == suite) { \
+		CU_cleanup_registry(); \
+		return CU_get_error(); } \
+	if (name##_add_tests(suite)) { \
+		CU_cleanup_registry(); \
+		return CU_get_error(); }
+
+static void usage(char *progname)
+{
+	printf("usage:  %s [options]\n", progname);
+	printf("options:\n");
+	printf("\t-v, --verbose\t\t\tverbose output\n");
+	printf("\t-i, --interactive\t\tinteractive console\n");
+}
+
+static int do_tests(int interactive, int verbose)
+{
+	CU_pSuite suite = NULL;
+
+	if (CUE_SUCCESS != CU_initialize_registry())
+		return CU_get_error();
+
+	DECLARE_SUITE(cond);
+	DECLARE_SUITE(linker);
+	DECLARE_SUITE(expander);
+	DECLARE_SUITE(deps);
+	DECLARE_SUITE(downgrade);
+
+	if (verbose)
+		CU_basic_set_mode(CU_BRM_VERBOSE);
+	else
+		CU_basic_set_mode(CU_BRM_NORMAL);
+
+	if (interactive)
+		CU_console_run_tests();
+	else
+		CU_basic_run_tests();
+	CU_cleanup_registry();
+	return CU_get_error();
+
+}
+
+int main(int argc, char **argv)
+{
+	int i, verbose = 1, interactive = 0;
+
+	struct option opts[] = {
+		{"verbose", 0, NULL, 'v'},
+		{"interactive", 0, NULL, 'i'},
+		{NULL, 0, NULL, 0}
+	};
+
+	while ((i = getopt_long(argc, argv, "vi", opts, NULL)) != -1) {
+		switch (i) {
+		case 'v':
+			verbose = 1;
+			break;
+		case 'i':
+			interactive = 1;
+			break;
+		case 'h':
+		default:{
+				usage(argv[0]);
+				exit(1);
+			}
+		}
+	}
+
+	/* first do the non-mls tests */
+	mls = 0;
+	if (do_tests(interactive, verbose))
+		return -1;
+
+	/* then with mls */
+	mls = 1;
+	if (do_tests(interactive, verbose))
+		return -1;
+
+	return 0;
+}
diff --git a/libsepol/tests/policies/support/misc_macros.spt b/libsepol/tests/policies/support/misc_macros.spt
new file mode 100644
index 0000000..5fadd0f
--- /dev/null
+++ b/libsepol/tests/policies/support/misc_macros.spt
@@ -0,0 +1,23 @@
+
+########################################
+#
+# Helper macros
+#
+
+########################################
+#
+# gen_user(username, prefix, role_set, mls_defaultlevel, mls_range, [mcs_categories])
+#
+define(`gen_user',`dnl
+ifdef(`users_extra',`dnl
+ifelse(`$2',,,`user $1 prefix $2;')
+',`dnl
+user $1 roles { $3 }`'ifdef(`enable_mls', ` level $4 range $5')`'ifdef(`enable_mcs',` level s0 range s0`'ifelse(`$6',,,` - s0:$6')');
+')dnl
+')
+
+########################################
+#
+# gen_context(context,mls_sensitivity,[mcs_categories])
+#
+define(`gen_context',`$1`'ifdef(`enable_mls',`:$2')`'ifdef(`enable_mcs',`:s0`'ifelse(`$3',,,`:$3')')') dnl
diff --git a/libsepol/tests/policies/test-cond/refpolicy-base.conf b/libsepol/tests/policies/test-cond/refpolicy-base.conf
new file mode 100644
index 0000000..1c1ef9a
--- /dev/null
+++ b/libsepol/tests/policies/test-cond/refpolicy-base.conf
@@ -0,0 +1,1940 @@
+class security
+class process
+class system
+class capability
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+class sem
+class msg
+class msgq
+class shm
+class ipc
+class passwd			# userspace
+class drawable			# userspace
+class window			# userspace
+class gc			# userspace
+class font			# userspace
+class colormap			# userspace
+class property			# userspace
+class cursor			# userspace
+class xclient			# userspace
+class xinput			# userspace
+class xserver			# userspace
+class xextension		# userspace
+class pax
+class netlink_route_socket
+class netlink_firewall_socket
+class netlink_tcpdiag_socket
+class netlink_nflog_socket
+class netlink_xfrm_socket
+class netlink_selinux_socket
+class netlink_audit_socket
+class netlink_ip6fw_socket
+class netlink_dnrt_socket
+class dbus			# userspace
+class nscd			# userspace
+class association
+class netlink_kobject_uevent_socket
+sid kernel
+sid security
+sid unlabeled
+sid fs
+sid file
+sid file_labels
+sid init
+sid any_socket
+sid port
+sid netif
+sid netmsg
+sid node
+sid igmp_packet
+sid icmp_socket
+sid tcp_socket
+sid sysctl_modprobe
+sid sysctl
+sid sysctl_fs
+sid sysctl_kernel
+sid sysctl_net
+sid sysctl_net_unix
+sid sysctl_vm
+sid sysctl_dev
+sid kmod
+sid policy
+sid scmp_packet
+sid devnull
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+common socket
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+	execmod
+}
+class lnk_file
+inherits file
+class chr_file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+	execmod
+}
+class blk_file
+inherits file
+class sock_file
+inherits file
+class fifo_file
+inherits file
+class fd
+{
+	use
+}
+class socket
+inherits socket
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+	node_bind
+	name_connect
+}
+class udp_socket
+inherits socket
+{
+	node_bind
+}
+class rawip_socket
+inherits socket
+{
+	node_bind
+}
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+class netlink_socket
+inherits socket
+class packet_socket
+inherits socket
+class key_socket
+inherits socket
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+class unix_dgram_socket
+inherits socket
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+	getattr
+	setexec
+	setfscreate
+	noatsecure
+	siginh
+	setrlimit
+	rlimitinh
+	dyntransition
+	setcurrent
+	execmem
+	execstack
+	execheap
+}
+class ipc
+inherits ipc
+class sem
+inherits ipc
+class msgq
+inherits ipc
+{
+	enqueue
+}
+class msg
+{
+	send
+	receive
+}
+class shm
+inherits ipc
+{
+	lock
+}
+class security
+{
+	compute_av
+	compute_create
+	compute_member
+	check_context
+	load_policy
+	compute_relabel
+	compute_user
+	setenforce     # was avc_toggle in system class
+	setbool
+	setsecparam
+	setcheckreqprot
+}
+class system
+{
+	ipc_info
+	syslog_read  
+	syslog_mod
+	syslog_console
+}
+class capability
+{
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+	audit_write
+	audit_control
+}
+class passwd
+{
+	passwd	# change another user passwd
+	chfn	# change another user finger info
+	chsh	# change another user shell
+	rootok  # pam_rootok check (skip auth)
+	crontab # crontab on another user
+}
+class drawable
+{
+	create
+	destroy
+	draw
+	copy
+	getattr
+}
+class gc
+{
+	create
+	free
+	getattr
+	setattr
+}
+class window 
+{
+	addchild
+	create
+	destroy
+	map
+	unmap
+	chstack
+	chproplist
+	chprop	
+	listprop
+	getattr
+	setattr
+	setfocus
+	move
+	chselection
+	chparent
+	ctrllife
+	enumerate
+	transparent
+	mousemotion
+	clientcomevent
+	inputevent
+	drawevent
+	windowchangeevent
+	windowchangerequest
+	serverchangeevent
+	extensionevent
+}
+class font
+{
+	load
+	free
+	getattr
+	use
+}
+class colormap
+{
+	create
+	free
+	install
+	uninstall
+	list
+	read
+	store
+	getattr
+	setattr
+}
+class property
+{
+	create
+	free
+	read
+	write
+}
+class cursor
+{
+	create
+	createglyph
+	free
+	assign
+	setattr
+}
+class xclient
+{
+	kill
+}
+class xinput
+{
+	lookup
+	getattr
+	setattr
+	setfocus
+	warppointer
+	activegrab
+	passivegrab
+	ungrab
+	bell
+	mousemotion
+	relabelinput
+}
+class xserver
+{
+	screensaver
+	gethostlist
+	sethostlist
+	getfontpath
+	setfontpath
+	getattr
+	grab
+	ungrab
+}
+class xextension
+{
+	query
+	use
+}
+class pax
+{
+	pageexec	# Paging based non-executable pages
+	emutramp	# Emulate trampolines
+	mprotect	# Restrict mprotect()
+	randmmap	# Randomize mmap() base
+	randexec	# Randomize ET_EXEC base
+	segmexec	# Segmentation based non-executable pages
+}
+class netlink_route_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+}
+class netlink_firewall_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+}
+class netlink_tcpdiag_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+}
+class netlink_nflog_socket
+inherits socket
+class netlink_xfrm_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+}
+class netlink_selinux_socket
+inherits socket
+class netlink_audit_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+	nlmsg_relay
+	nlmsg_readpriv
+}
+class netlink_ip6fw_socket
+inherits socket
+{
+	nlmsg_read
+	nlmsg_write
+}
+class netlink_dnrt_socket
+inherits socket
+class dbus
+{
+	acquire_svc
+	send_msg
+}
+class nscd
+{
+	getpwd
+	getgrp
+	gethost
+	getstat
+	admin
+	shmempwd
+	shmemgrp
+	shmemhost
+}
+class association
+{
+	sendto
+	recvfrom
+	setcontext
+}
+class netlink_kobject_uevent_socket
+inherits socket
+sensitivity s0;
+dominance { s0 }
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+category c24; category c25; category c26; category c27;
+category c28; category c29; category c30; category c31;
+category c32; category c33; category c34; category c35;
+category c36; category c37; category c38; category c39;
+category c40; category c41; category c42; category c43;
+category c44; category c45; category c46; category c47;
+category c48; category c49; category c50; category c51;
+category c52; category c53; category c54; category c55;
+category c56; category c57; category c58; category c59;
+category c60; category c61; category c62; category c63;
+category c64; category c65; category c66; category c67;
+category c68; category c69; category c70; category c71;
+category c72; category c73; category c74; category c75;
+category c76; category c77; category c78; category c79;
+category c80; category c81; category c82; category c83;
+category c84; category c85; category c86; category c87;
+category c88; category c89; category c90; category c91;
+category c92; category c93; category c94; category c95;
+category c96; category c97; category c98; category c99;
+category c100; category c101; category c102; category c103;
+category c104; category c105; category c106; category c107;
+category c108; category c109; category c110; category c111;
+category c112; category c113; category c114; category c115;
+category c116; category c117; category c118; category c119;
+category c120; category c121; category c122; category c123;
+category c124; category c125; category c126; category c127;
+category c128; category c129; category c130; category c131;
+category c132; category c133; category c134; category c135;
+category c136; category c137; category c138; category c139;
+category c140; category c141; category c142; category c143;
+category c144; category c145; category c146; category c147;
+category c148; category c149; category c150; category c151;
+category c152; category c153; category c154; category c155;
+category c156; category c157; category c158; category c159;
+category c160; category c161; category c162; category c163;
+category c164; category c165; category c166; category c167;
+category c168; category c169; category c170; category c171;
+category c172; category c173; category c174; category c175;
+category c176; category c177; category c178; category c179;
+category c180; category c181; category c182; category c183;
+category c184; category c185; category c186; category c187;
+category c188; category c189; category c190; category c191;
+category c192; category c193; category c194; category c195;
+category c196; category c197; category c198; category c199;
+category c200; category c201; category c202; category c203;
+category c204; category c205; category c206; category c207;
+category c208; category c209; category c210; category c211;
+category c212; category c213; category c214; category c215;
+category c216; category c217; category c218; category c219;
+category c220; category c221; category c222; category c223;
+category c224; category c225; category c226; category c227;
+category c228; category c229; category c230; category c231;
+category c232; category c233; category c234; category c235;
+category c236; category c237; category c238; category c239;
+category c240; category c241; category c242; category c243;
+category c244; category c245; category c246; category c247;
+category c248; category c249; category c250; category c251;
+category c252; category c253; category c254; category c255;
+level s0:c0.c255;
+mlsconstrain file { write setattr append unlink link rename
+		    ioctl lock execute relabelfrom } (h1 dom h2);
+mlsconstrain file { create relabelto } ((h1 dom h2) and (l2 eq h2));
+mlsconstrain file { read } ((h1 dom h2) or ( t2 == domain ) or ( t1 == mlsfileread ));
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { relabelfrom }
+	( h1 dom h2 );
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { create relabelto }
+	(( h1 dom h2 ) and ( l2 eq h2 ));
+mlsconstrain process { ptrace } ( h1 dom h2 );
+mlsconstrain process { sigkill sigstop } ( h1 dom h2 ) or
+		( t1 == mcskillall );
+mlsconstrain xextension query ( t1 == mlsfileread );
+attribute netif_type;
+attribute node_type;
+attribute port_type;
+attribute reserved_port_type;
+attribute device_node;
+attribute memory_raw_read;
+attribute memory_raw_write;
+attribute domain;
+attribute unconfined_domain_type;
+attribute set_curr_context;
+attribute entry_type;
+attribute privfd;
+attribute can_change_process_identity;
+attribute can_change_process_role;
+attribute can_change_object_identity;
+attribute can_system_change;
+attribute process_user_target;
+attribute cron_source_domain;
+attribute cron_job_domain;
+attribute process_uncond_exempt;	# add userhelperdomain to this one
+attribute file_type;
+attribute lockfile;
+attribute mountpoint;
+attribute pidfile;
+attribute polydir;
+attribute usercanread;
+attribute polyparent;
+attribute polymember;
+attribute security_file_type;
+attribute tmpfile;
+attribute tmpfsfile;
+attribute filesystem_type;
+attribute noxattrfs;
+attribute can_load_kernmodule;
+attribute can_receive_kernel_messages;
+attribute kern_unconfined;
+attribute proc_type;
+attribute sysctl_type;
+attribute mcskillall;
+attribute mlsfileread;
+attribute mlsfilereadtoclr;
+attribute mlsfilewrite;
+attribute mlsfilewritetoclr;
+attribute mlsfileupgrade;
+attribute mlsfiledowngrade;
+attribute mlsnetread;
+attribute mlsnetreadtoclr;
+attribute mlsnetwrite;
+attribute mlsnetwritetoclr;
+attribute mlsnetupgrade;
+attribute mlsnetdowngrade;
+attribute mlsnetrecvall;
+attribute mlsipcread;
+attribute mlsipcreadtoclr;
+attribute mlsipcwrite;
+attribute mlsipcwritetoclr;
+attribute mlsprocread;
+attribute mlsprocreadtoclr;
+attribute mlsprocwrite;
+attribute mlsprocwritetoclr;
+attribute mlsprocsetsl;
+attribute mlsxwinread;
+attribute mlsxwinreadtoclr;
+attribute mlsxwinwrite;
+attribute mlsxwinwritetoclr;
+attribute mlsxwinreadproperty;
+attribute mlsxwinwriteproperty;
+attribute mlsxwinreadcolormap;
+attribute mlsxwinwritecolormap;
+attribute mlsxwinwritexinput;
+attribute mlstrustedobject;
+attribute privrangetrans;
+attribute mlsrangetrans;
+attribute can_load_policy;
+attribute can_setenforce;
+attribute can_setsecparam;
+attribute ttynode;
+attribute ptynode;
+attribute server_ptynode;
+attribute serial_device;
+type bin_t;
+type sbin_t;
+type ls_exec_t;
+type shell_exec_t;
+type chroot_exec_t;
+type ppp_device_t;
+type tun_tap_device_t;
+type port_t, port_type;
+type reserved_port_t, port_type, reserved_port_type;
+type afs_bos_port_t, port_type;
+type afs_fs_port_t, port_type;
+type afs_ka_port_t, port_type;
+type afs_pt_port_t, port_type;
+type afs_vl_port_t, port_type;
+type amanda_port_t, port_type;
+type amavisd_recv_port_t, port_type;
+type amavisd_send_port_t, port_type;
+type asterisk_port_t, port_type;
+type auth_port_t, port_type;
+type bgp_port_t, port_type;
+type biff_port_t, port_type, reserved_port_type; 
+type clamd_port_t, port_type;
+type clockspeed_port_t, port_type;
+type comsat_port_t, port_type;
+type cvs_port_t, port_type;
+type dcc_port_t, port_type;
+type dbskkd_port_t, port_type;
+type dhcpc_port_t, port_type;
+type dhcpd_port_t, port_type;
+type dict_port_t, port_type;
+type distccd_port_t, port_type;
+type dns_port_t, port_type;
+type fingerd_port_t, port_type;
+type ftp_data_port_t, port_type;
+type ftp_port_t, port_type;
+type gatekeeper_port_t, port_type;
+type giftd_port_t, port_type;
+type gopher_port_t, port_type;
+type http_cache_port_t, port_type;
+type http_port_t, port_type;
+type howl_port_t, port_type;
+type hplip_port_t, port_type;
+type i18n_input_port_t, port_type;
+type imaze_port_t, port_type;
+type inetd_child_port_t, port_type;
+type innd_port_t, port_type;
+type ipp_port_t, port_type;
+type ircd_port_t, port_type;
+type isakmp_port_t, port_type;
+type jabber_client_port_t, port_type;
+type jabber_interserver_port_t, port_type;
+type kerberos_admin_port_t, port_type;
+type kerberos_master_port_t, port_type;
+type kerberos_port_t, port_type;
+type ktalkd_port_t, port_type;
+type ldap_port_t, port_type;
+type lrrd_port_t, port_type; 
+type mail_port_t, port_type;
+type monopd_port_t, port_type;
+type mysqld_port_t, port_type;
+type nessus_port_t, port_type;
+type nmbd_port_t, port_type;
+type ntp_port_t, port_type;
+type openvpn_port_t, port_type;
+type pegasus_http_port_t, port_type;
+type pegasus_https_port_t, port_type;
+type pop_port_t, port_type;
+type portmap_port_t, port_type;
+type postgresql_port_t, port_type;
+type postgrey_port_t, port_type;
+type printer_port_t, port_type;
+type ptal_port_t, port_type;
+type pxe_port_t, port_type;
+type pyzor_port_t, port_type;
+type radacct_port_t, port_type;
+type radius_port_t, port_type;
+type razor_port_t, port_type;
+type rlogind_port_t, port_type;
+type rndc_port_t, port_type;
+type router_port_t, port_type;
+type rsh_port_t, port_type;
+type rsync_port_t, port_type;
+type smbd_port_t, port_type;
+type smtp_port_t, port_type;
+type snmp_port_t, port_type;
+type spamd_port_t, port_type;
+type ssh_port_t, port_type;
+type soundd_port_t, port_type;
+type socks_port_t, port_type; type stunnel_port_t, port_type; 
+type swat_port_t, port_type;
+type syslogd_port_t, port_type;
+type telnetd_port_t, port_type;
+type tftp_port_t, port_type;
+type transproxy_port_t, port_type;
+type utcpserver_port_t, port_type; 
+type uucpd_port_t, port_type;
+type vnc_port_t, port_type;
+type xserver_port_t, port_type;
+type xen_port_t, port_type;
+type zebra_port_t, port_type;
+type zope_port_t, port_type;
+type node_t, node_type;
+type compat_ipv4_node_t alias node_compat_ipv4_t, node_type;
+type inaddr_any_node_t alias node_inaddr_any_t, node_type;
+type node_internal_t, node_type; 
+type link_local_node_t alias node_link_local_t, node_type;
+type lo_node_t alias node_lo_t, node_type;
+type mapped_ipv4_node_t alias node_mapped_ipv4_t, node_type;
+type multicast_node_t alias node_multicast_t, node_type;
+type site_local_node_t alias node_site_local_t, node_type;
+type unspec_node_t alias node_unspec_t, node_type;
+type netif_t, netif_type;
+type device_t;
+type agp_device_t;
+type apm_bios_t;
+type cardmgr_dev_t;
+type clock_device_t;
+type cpu_device_t;
+type crypt_device_t;
+type dri_device_t;
+type event_device_t;
+type framebuf_device_t;
+type lvm_control_t;
+type memory_device_t;
+type misc_device_t;
+type mouse_device_t;
+type mtrr_device_t;
+type null_device_t;
+type power_device_t;
+type printer_device_t;
+type random_device_t;
+type scanner_device_t;
+type sound_device_t;
+type sysfs_t;
+type urandom_device_t;
+type usbfs_t alias usbdevfs_t;
+type usb_device_t;
+type v4l_device_t;
+type xserver_misc_device_t;
+type zero_device_t;
+type xconsole_device_t;
+type devfs_control_t;
+type boot_t;
+type default_t, file_type, mountpoint;
+type etc_t, file_type;
+type etc_runtime_t, file_type;
+type file_t, file_type, mountpoint;
+type home_root_t, file_type, mountpoint;
+type lost_found_t, file_type;
+type mnt_t, file_type, mountpoint;
+type modules_object_t;
+type no_access_t, file_type;
+type poly_t, file_type;
+type readable_t, file_type;
+type root_t, file_type, mountpoint;
+type src_t, file_type, mountpoint;
+type system_map_t;
+type tmp_t, mountpoint; #, polydir
+type usr_t, file_type, mountpoint;
+type var_t, file_type, mountpoint;
+type var_lib_t, file_type, mountpoint;
+type var_lock_t, file_type, lockfile;
+type var_run_t, file_type, pidfile;
+type var_spool_t;
+type fs_t;
+type bdev_t;
+type binfmt_misc_fs_t;
+type capifs_t;
+type configfs_t;
+type eventpollfs_t;
+type futexfs_t;
+type hugetlbfs_t;
+type inotifyfs_t;
+type nfsd_fs_t;
+type ramfs_t;
+type romfs_t;
+type rpc_pipefs_t;
+type tmpfs_t;
+type autofs_t, noxattrfs;
+type cifs_t alias sambafs_t, noxattrfs;
+type dosfs_t, noxattrfs;
+type iso9660_t, filesystem_type, noxattrfs;
+type removable_t, noxattrfs;
+type nfs_t, filesystem_type, noxattrfs;
+type kernel_t, can_load_kernmodule;
+type debugfs_t;
+type proc_t, proc_type;
+type proc_kmsg_t, proc_type;
+type proc_kcore_t, proc_type;
+type proc_mdstat_t, proc_type;
+type proc_net_t, proc_type;
+type proc_xen_t, proc_type;
+type sysctl_t, sysctl_type;
+type sysctl_irq_t, sysctl_type;
+type sysctl_rpc_t, sysctl_type;
+type sysctl_fs_t, sysctl_type;
+type sysctl_kernel_t, sysctl_type;
+type sysctl_modprobe_t, sysctl_type;
+type sysctl_hotplug_t, sysctl_type;
+type sysctl_net_t, sysctl_type;
+type sysctl_net_unix_t, sysctl_type;
+type sysctl_vm_t, sysctl_type;
+type sysctl_dev_t, sysctl_type;
+type unlabeled_t;
+type auditd_exec_t;
+type crond_exec_t;
+type cupsd_exec_t;
+type getty_t;
+type init_t;
+type init_exec_t;
+type initrc_t;
+type initrc_exec_t;
+type login_exec_t;
+type sshd_exec_t;
+type su_exec_t;
+type udev_exec_t;
+type unconfined_t;
+type xdm_exec_t;
+type lvm_exec_t;
+type security_t;
+type bsdpty_device_t;
+type console_device_t;
+type devpts_t;
+type devtty_t;
+type ptmx_t;
+type tty_device_t, serial_device;
+type usbtty_device_t, serial_device;
+	bool secure_mode false;
+	bool secure_mode_insmod false;
+	bool secure_mode_policyload false;
+		bool allow_cvs_read_shadow false;
+		bool allow_execheap false;
+		bool allow_execmem true;
+		bool allow_execmod false;
+		bool allow_execstack true;
+		bool allow_ftpd_anon_write false;
+		bool allow_gssd_read_tmp true;
+		bool allow_httpd_anon_write false;
+		bool allow_java_execstack false;
+		bool allow_kerberos true;
+		bool allow_rsync_anon_write false;
+		bool allow_saslauthd_read_shadow false;
+		bool allow_smbd_anon_write false;
+		bool allow_ptrace false;
+		bool allow_ypbind false;
+		bool fcron_crond false;
+		bool ftp_home_dir false;
+		bool ftpd_is_daemon true;
+		bool httpd_builtin_scripting true;
+		bool httpd_can_network_connect false;
+		bool httpd_can_network_connect_db false;
+		bool httpd_can_network_relay false;
+		bool httpd_enable_cgi true;
+		bool httpd_enable_ftp_server false;
+		bool httpd_enable_homedirs true;
+		bool httpd_ssi_exec true;
+		bool httpd_tty_comm false;
+		bool httpd_unified true;
+		bool named_write_master_zones false;
+		bool nfs_export_all_rw true;
+		bool nfs_export_all_ro true;
+		bool pppd_can_insmod false;
+		bool read_default_t true;
+		bool run_ssh_inetd false;
+		bool samba_enable_home_dirs false;
+		bool spamassasin_can_network false;
+		bool squid_connect_any false;
+		bool ssh_sysadm_login false;
+		bool stunnel_is_daemon false;
+		bool use_nfs_home_dirs false;
+		bool use_samba_home_dirs false;
+		bool user_ping true;
+		bool spamd_enable_home_dirs true;
+	allow bin_t fs_t:filesystem associate;
+	allow bin_t noxattrfs:filesystem associate;
+	typeattribute bin_t file_type;
+	allow sbin_t fs_t:filesystem associate;
+	allow sbin_t noxattrfs:filesystem associate;
+	typeattribute sbin_t file_type;
+	allow ls_exec_t fs_t:filesystem associate;
+	allow ls_exec_t noxattrfs:filesystem associate;
+	typeattribute ls_exec_t file_type;
+typeattribute ls_exec_t entry_type;
+	allow shell_exec_t fs_t:filesystem associate;
+	allow shell_exec_t noxattrfs:filesystem associate;
+	typeattribute shell_exec_t file_type;
+	allow chroot_exec_t fs_t:filesystem associate;
+	allow chroot_exec_t noxattrfs:filesystem associate;
+	typeattribute chroot_exec_t file_type;
+	typeattribute ppp_device_t device_node;
+	allow ppp_device_t fs_t:filesystem associate;
+	allow ppp_device_t tmpfs_t:filesystem associate;
+	allow ppp_device_t tmp_t:filesystem associate;
+	typeattribute tun_tap_device_t device_node;
+	allow tun_tap_device_t fs_t:filesystem associate;
+	allow tun_tap_device_t tmpfs_t:filesystem associate;
+	allow tun_tap_device_t tmp_t:filesystem associate;
+typeattribute auth_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute comsat_port_t reserved_port_type;
+typeattribute dhcpc_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute fingerd_port_t reserved_port_type;
+typeattribute ftp_data_port_t reserved_port_type;
+typeattribute ftp_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute innd_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute isakmp_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute ntp_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute printer_port_t reserved_port_type;
+typeattribute rlogind_port_t reserved_port_type;
+typeattribute rndc_port_t reserved_port_type;
+typeattribute router_port_t reserved_port_type;
+typeattribute rsh_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute spamd_port_t reserved_port_type;
+typeattribute ssh_port_t reserved_port_type;
+typeattribute swat_port_t reserved_port_type;
+typeattribute syslogd_port_t reserved_port_type;
+typeattribute telnetd_port_t reserved_port_type;
+typeattribute tftp_port_t reserved_port_type;
+typeattribute uucpd_port_t reserved_port_type;
+	allow device_t tmpfs_t:filesystem associate;
+	allow device_t fs_t:filesystem associate;
+	allow device_t noxattrfs:filesystem associate;
+	typeattribute device_t file_type;
+	allow device_t fs_t:filesystem associate;
+	allow device_t noxattrfs:filesystem associate;
+	typeattribute device_t file_type;
+	typeattribute device_t mountpoint;
+	allow device_t tmp_t:filesystem associate;
+	typeattribute agp_device_t device_node;
+	allow agp_device_t fs_t:filesystem associate;
+	allow agp_device_t tmpfs_t:filesystem associate;
+	allow agp_device_t tmp_t:filesystem associate;
+	typeattribute apm_bios_t device_node;
+	allow apm_bios_t fs_t:filesystem associate;
+	allow apm_bios_t tmpfs_t:filesystem associate;
+	allow apm_bios_t tmp_t:filesystem associate;
+	typeattribute cardmgr_dev_t device_node;
+	allow cardmgr_dev_t fs_t:filesystem associate;
+	allow cardmgr_dev_t tmpfs_t:filesystem associate;
+	allow cardmgr_dev_t tmp_t:filesystem associate;
+	allow cardmgr_dev_t fs_t:filesystem associate;
+	allow cardmgr_dev_t noxattrfs:filesystem associate;
+	typeattribute cardmgr_dev_t file_type;
+	allow cardmgr_dev_t fs_t:filesystem associate;
+	allow cardmgr_dev_t noxattrfs:filesystem associate;
+	typeattribute cardmgr_dev_t file_type;
+	typeattribute cardmgr_dev_t polymember;
+	allow cardmgr_dev_t tmpfs_t:filesystem associate;
+	typeattribute cardmgr_dev_t tmpfile;
+	allow cardmgr_dev_t tmp_t:filesystem associate;
+	typeattribute clock_device_t device_node;
+	allow clock_device_t fs_t:filesystem associate;
+	allow clock_device_t tmpfs_t:filesystem associate;
+	allow clock_device_t tmp_t:filesystem associate;
+	typeattribute cpu_device_t device_node;
+	allow cpu_device_t fs_t:filesystem associate;
+	allow cpu_device_t tmpfs_t:filesystem associate;
+	allow cpu_device_t tmp_t:filesystem associate;
+	typeattribute crypt_device_t device_node;
+	allow crypt_device_t fs_t:filesystem associate;
+	allow crypt_device_t tmpfs_t:filesystem associate;
+	allow crypt_device_t tmp_t:filesystem associate;
+	typeattribute dri_device_t device_node;
+	allow dri_device_t fs_t:filesystem associate;
+	allow dri_device_t tmpfs_t:filesystem associate;
+	allow dri_device_t tmp_t:filesystem associate;
+	typeattribute event_device_t device_node;
+	allow event_device_t fs_t:filesystem associate;
+	allow event_device_t tmpfs_t:filesystem associate;
+	allow event_device_t tmp_t:filesystem associate;
+	typeattribute framebuf_device_t device_node;
+	allow framebuf_device_t fs_t:filesystem associate;
+	allow framebuf_device_t tmpfs_t:filesystem associate;
+	allow framebuf_device_t tmp_t:filesystem associate;
+	typeattribute lvm_control_t device_node;
+	allow lvm_control_t fs_t:filesystem associate;
+	allow lvm_control_t tmpfs_t:filesystem associate;
+	allow lvm_control_t tmp_t:filesystem associate;
+	typeattribute memory_device_t device_node;
+	allow memory_device_t fs_t:filesystem associate;
+	allow memory_device_t tmpfs_t:filesystem associate;
+	allow memory_device_t tmp_t:filesystem associate;
+neverallow ~memory_raw_read memory_device_t:{ chr_file blk_file } read;
+neverallow ~memory_raw_write memory_device_t:{ chr_file blk_file } { append write };
+	typeattribute misc_device_t device_node;
+	allow misc_device_t fs_t:filesystem associate;
+	allow misc_device_t tmpfs_t:filesystem associate;
+	allow misc_device_t tmp_t:filesystem associate;
+	typeattribute mouse_device_t device_node;
+	allow mouse_device_t fs_t:filesystem associate;
+	allow mouse_device_t tmpfs_t:filesystem associate;
+	allow mouse_device_t tmp_t:filesystem associate;
+	typeattribute mtrr_device_t device_node;
+	allow mtrr_device_t fs_t:filesystem associate;
+	allow mtrr_device_t tmpfs_t:filesystem associate;
+	allow mtrr_device_t tmp_t:filesystem associate;
+	typeattribute null_device_t device_node;
+	allow null_device_t fs_t:filesystem associate;
+	allow null_device_t tmpfs_t:filesystem associate;
+	allow null_device_t tmp_t:filesystem associate;
+	typeattribute null_device_t mlstrustedobject;
+	typeattribute power_device_t device_node;
+	allow power_device_t fs_t:filesystem associate;
+	allow power_device_t tmpfs_t:filesystem associate;
+	allow power_device_t tmp_t:filesystem associate;
+	typeattribute printer_device_t device_node;
+	allow printer_device_t fs_t:filesystem associate;
+	allow printer_device_t tmpfs_t:filesystem associate;
+	allow printer_device_t tmp_t:filesystem associate;
+	typeattribute random_device_t device_node;
+	allow random_device_t fs_t:filesystem associate;
+	allow random_device_t tmpfs_t:filesystem associate;
+	allow random_device_t tmp_t:filesystem associate;
+	typeattribute scanner_device_t device_node;
+	allow scanner_device_t fs_t:filesystem associate;
+	allow scanner_device_t tmpfs_t:filesystem associate;
+	allow scanner_device_t tmp_t:filesystem associate;
+	typeattribute sound_device_t device_node;
+	allow sound_device_t fs_t:filesystem associate;
+	allow sound_device_t tmpfs_t:filesystem associate;
+	allow sound_device_t tmp_t:filesystem associate;
+	allow sysfs_t fs_t:filesystem associate;
+	allow sysfs_t noxattrfs:filesystem associate;
+	typeattribute sysfs_t file_type;
+	typeattribute sysfs_t mountpoint;
+	typeattribute sysfs_t filesystem_type;
+	allow sysfs_t self:filesystem associate;
+	typeattribute urandom_device_t device_node;
+	allow urandom_device_t fs_t:filesystem associate;
+	allow urandom_device_t tmpfs_t:filesystem associate;
+	allow urandom_device_t tmp_t:filesystem associate;
+	allow usbfs_t fs_t:filesystem associate;
+	allow usbfs_t noxattrfs:filesystem associate;
+	typeattribute usbfs_t file_type;
+	typeattribute usbfs_t mountpoint;
+	typeattribute usbfs_t filesystem_type;
+	allow usbfs_t self:filesystem associate;
+	typeattribute usbfs_t noxattrfs;
+	typeattribute usb_device_t device_node;
+	allow usb_device_t fs_t:filesystem associate;
+	allow usb_device_t tmpfs_t:filesystem associate;
+	allow usb_device_t tmp_t:filesystem associate;
+	typeattribute v4l_device_t device_node;
+	allow v4l_device_t fs_t:filesystem associate;
+	allow v4l_device_t tmpfs_t:filesystem associate;
+	allow v4l_device_t tmp_t:filesystem associate;
+	typeattribute xserver_misc_device_t device_node;
+	allow xserver_misc_device_t fs_t:filesystem associate;
+	allow xserver_misc_device_t tmpfs_t:filesystem associate;
+	allow xserver_misc_device_t tmp_t:filesystem associate;
+	typeattribute zero_device_t device_node;
+	allow zero_device_t fs_t:filesystem associate;
+	allow zero_device_t tmpfs_t:filesystem associate;
+	allow zero_device_t tmp_t:filesystem associate;
+	typeattribute zero_device_t mlstrustedobject;
+	allow xconsole_device_t fs_t:filesystem associate;
+	allow xconsole_device_t noxattrfs:filesystem associate;
+	typeattribute xconsole_device_t file_type;
+	allow xconsole_device_t tmpfs_t:filesystem associate;
+	allow xconsole_device_t tmp_t:filesystem associate;
+	typeattribute devfs_control_t device_node;
+	allow devfs_control_t fs_t:filesystem associate;
+	allow devfs_control_t tmpfs_t:filesystem associate;
+	allow devfs_control_t tmp_t:filesystem associate;
+neverallow domain ~domain:process { transition dyntransition };
+neverallow { domain -set_curr_context } self:process setcurrent;
+neverallow { domain unlabeled_t } ~{ domain unlabeled_t }:process *;
+neverallow ~{ domain unlabeled_t } *:process *;
+allow file_type self:filesystem associate;
+	allow boot_t fs_t:filesystem associate;
+	allow boot_t noxattrfs:filesystem associate;
+	typeattribute boot_t file_type;
+	allow boot_t fs_t:filesystem associate;
+	allow boot_t noxattrfs:filesystem associate;
+	typeattribute boot_t file_type;
+	typeattribute boot_t mountpoint;
+	allow default_t fs_t:filesystem associate;
+	allow default_t noxattrfs:filesystem associate;
+	allow etc_t fs_t:filesystem associate;
+	allow etc_t noxattrfs:filesystem associate;
+	allow etc_runtime_t fs_t:filesystem associate;
+	allow etc_runtime_t noxattrfs:filesystem associate;
+	allow file_t fs_t:filesystem associate;
+	allow file_t noxattrfs:filesystem associate;
+	allow kernel_t file_t:dir mounton;
+	allow home_root_t fs_t:filesystem associate;
+	allow home_root_t noxattrfs:filesystem associate;
+	allow home_root_t fs_t:filesystem associate;
+	allow home_root_t noxattrfs:filesystem associate;
+	typeattribute home_root_t file_type;
+	typeattribute home_root_t polyparent;
+	allow lost_found_t fs_t:filesystem associate;
+	allow lost_found_t noxattrfs:filesystem associate;
+	allow mnt_t fs_t:filesystem associate;
+	allow mnt_t noxattrfs:filesystem associate;
+	allow modules_object_t fs_t:filesystem associate;
+	allow modules_object_t noxattrfs:filesystem associate;
+	typeattribute modules_object_t file_type;
+	allow no_access_t fs_t:filesystem associate;
+	allow no_access_t noxattrfs:filesystem associate;
+	allow poly_t fs_t:filesystem associate;
+	allow poly_t noxattrfs:filesystem associate;
+	allow readable_t fs_t:filesystem associate;
+	allow readable_t noxattrfs:filesystem associate;
+	allow root_t fs_t:filesystem associate;
+	allow root_t noxattrfs:filesystem associate;
+	allow root_t fs_t:filesystem associate;
+	allow root_t noxattrfs:filesystem associate;
+	typeattribute root_t file_type;
+	typeattribute root_t polyparent;
+	allow kernel_t root_t:dir mounton;
+	allow src_t fs_t:filesystem associate;
+	allow src_t noxattrfs:filesystem associate;
+	allow system_map_t fs_t:filesystem associate;
+	allow system_map_t noxattrfs:filesystem associate;
+	typeattribute system_map_t file_type;
+	allow tmp_t fs_t:filesystem associate;
+	allow tmp_t noxattrfs:filesystem associate;
+	typeattribute tmp_t file_type;
+	allow tmp_t fs_t:filesystem associate;
+	allow tmp_t noxattrfs:filesystem associate;
+	typeattribute tmp_t file_type;
+	typeattribute tmp_t polymember;
+	allow tmp_t tmpfs_t:filesystem associate;
+	typeattribute tmp_t tmpfile;
+	allow tmp_t tmp_t:filesystem associate;
+	allow tmp_t fs_t:filesystem associate;
+	allow tmp_t noxattrfs:filesystem associate;
+	typeattribute tmp_t file_type;
+	typeattribute tmp_t polyparent;
+	allow usr_t fs_t:filesystem associate;
+	allow usr_t noxattrfs:filesystem associate;
+	allow var_t fs_t:filesystem associate;
+	allow var_t noxattrfs:filesystem associate;
+	allow var_lib_t fs_t:filesystem associate;
+	allow var_lib_t noxattrfs:filesystem associate;
+	allow var_lock_t fs_t:filesystem associate;
+	allow var_lock_t noxattrfs:filesystem associate;
+	allow var_run_t fs_t:filesystem associate;
+	allow var_run_t noxattrfs:filesystem associate;
+	allow var_spool_t fs_t:filesystem associate;
+	allow var_spool_t noxattrfs:filesystem associate;
+	typeattribute var_spool_t file_type;
+	allow var_spool_t fs_t:filesystem associate;
+	allow var_spool_t noxattrfs:filesystem associate;
+	typeattribute var_spool_t file_type;
+	typeattribute var_spool_t polymember;
+	allow var_spool_t tmpfs_t:filesystem associate;
+	typeattribute var_spool_t tmpfile;
+	allow var_spool_t tmp_t:filesystem associate;
+	typeattribute fs_t filesystem_type;
+	allow fs_t self:filesystem associate;
+	typeattribute bdev_t filesystem_type;
+	allow bdev_t self:filesystem associate;
+	typeattribute binfmt_misc_fs_t filesystem_type;
+	allow binfmt_misc_fs_t self:filesystem associate;
+	allow binfmt_misc_fs_t fs_t:filesystem associate;
+	allow binfmt_misc_fs_t noxattrfs:filesystem associate;
+	typeattribute binfmt_misc_fs_t file_type;
+	typeattribute binfmt_misc_fs_t mountpoint;
+	typeattribute capifs_t filesystem_type;
+	allow capifs_t self:filesystem associate;
+	typeattribute configfs_t filesystem_type;
+	allow configfs_t self:filesystem associate;
+	typeattribute eventpollfs_t filesystem_type;
+	allow eventpollfs_t self:filesystem associate;
+	typeattribute futexfs_t filesystem_type;
+	allow futexfs_t self:filesystem associate;
+	typeattribute hugetlbfs_t filesystem_type;
+	allow hugetlbfs_t self:filesystem associate;
+	allow hugetlbfs_t fs_t:filesystem associate;
+	allow hugetlbfs_t noxattrfs:filesystem associate;
+	typeattribute hugetlbfs_t file_type;
+	typeattribute hugetlbfs_t mountpoint;
+	typeattribute inotifyfs_t filesystem_type;
+	allow inotifyfs_t self:filesystem associate;
+	typeattribute nfsd_fs_t filesystem_type;
+	allow nfsd_fs_t self:filesystem associate;
+	typeattribute ramfs_t filesystem_type;
+	allow ramfs_t self:filesystem associate;
+	typeattribute romfs_t filesystem_type;
+	allow romfs_t self:filesystem associate;
+	typeattribute rpc_pipefs_t filesystem_type;
+	allow rpc_pipefs_t self:filesystem associate;
+	typeattribute tmpfs_t filesystem_type;
+	allow tmpfs_t self:filesystem associate;
+	allow tmpfs_t fs_t:filesystem associate;
+	allow tmpfs_t noxattrfs:filesystem associate;
+	typeattribute tmpfs_t file_type;
+	allow tmpfs_t fs_t:filesystem associate;
+	allow tmpfs_t noxattrfs:filesystem associate;
+	typeattribute tmpfs_t file_type;
+	typeattribute tmpfs_t mountpoint;
+allow tmpfs_t noxattrfs:filesystem associate;
+	typeattribute autofs_t filesystem_type;
+	allow autofs_t self:filesystem associate;
+	allow autofs_t fs_t:filesystem associate;
+	allow autofs_t noxattrfs:filesystem associate;
+	typeattribute autofs_t file_type;
+	typeattribute autofs_t mountpoint;
+	typeattribute cifs_t filesystem_type;
+	allow cifs_t self:filesystem associate;
+	typeattribute dosfs_t filesystem_type;
+	allow dosfs_t self:filesystem associate;
+allow dosfs_t fs_t:filesystem associate;
+	typeattribute iso9660_t filesystem_type;
+	allow iso9660_t self:filesystem associate;
+allow removable_t noxattrfs:filesystem associate;
+	typeattribute removable_t filesystem_type;
+	allow removable_t self:filesystem associate;
+	allow removable_t fs_t:filesystem associate;
+	allow removable_t noxattrfs:filesystem associate;
+	typeattribute removable_t file_type;
+	typeattribute removable_t usercanread;
+	typeattribute nfs_t filesystem_type;
+	allow nfs_t self:filesystem associate;
+	allow nfs_t fs_t:filesystem associate;
+	allow nfs_t noxattrfs:filesystem associate;
+	typeattribute nfs_t file_type;
+	typeattribute nfs_t mountpoint;
+neverallow ~can_load_kernmodule self:capability sys_module;
+role system_r;
+role sysadm_r;
+role staff_r;
+role user_r;
+role secadm_r;
+	typeattribute kernel_t domain;
+	allow kernel_t self:dir { read getattr lock search ioctl };
+	allow kernel_t self:lnk_file { read getattr lock ioctl };
+	allow kernel_t self:file { getattr read write append ioctl lock };
+	allow kernel_t self:process { fork sigchld };
+		role secadm_r types kernel_t;
+		role sysadm_r types kernel_t;
+		role user_r types kernel_t;
+		role staff_r types kernel_t;
+	typeattribute kernel_t privrangetrans;
+role system_r types kernel_t;
+	typeattribute debugfs_t filesystem_type;
+	allow debugfs_t self:filesystem associate;
+allow debugfs_t self:filesystem associate;
+	allow proc_t fs_t:filesystem associate;
+	allow proc_t noxattrfs:filesystem associate;
+	typeattribute proc_t file_type;
+	typeattribute proc_t mountpoint;
+	typeattribute proc_t filesystem_type;
+	allow proc_t self:filesystem associate;
+neverallow ~can_receive_kernel_messages proc_kmsg_t:file ~getattr;
+neverallow { domain -kern_unconfined } proc_kcore_t:file ~getattr;
+	allow sysctl_t fs_t:filesystem associate;
+	allow sysctl_t noxattrfs:filesystem associate;
+	typeattribute sysctl_t file_type;
+	typeattribute sysctl_t mountpoint;
+	allow sysctl_fs_t fs_t:filesystem associate;
+	allow sysctl_fs_t noxattrfs:filesystem associate;
+	typeattribute sysctl_fs_t file_type;
+	typeattribute sysctl_fs_t mountpoint;
+allow kernel_t self:capability *;
+allow kernel_t unlabeled_t:dir mounton;
+allow kernel_t self:process ~{ ptrace setcurrent setexec setfscreate setrlimit execmem execstack execheap };
+allow kernel_t self:shm { associate getattr setattr create destroy read write lock unix_read unix_write };
+allow kernel_t self:sem { associate getattr setattr create destroy read write unix_read unix_write };
+allow kernel_t self:msg { send receive };
+allow kernel_t self:msgq { associate getattr setattr create destroy read write enqueue unix_read unix_write };
+allow kernel_t self:unix_dgram_socket { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } };
+allow kernel_t self:unix_stream_socket { { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } } listen accept };
+allow kernel_t self:unix_dgram_socket sendto;
+allow kernel_t self:unix_stream_socket connectto;
+allow kernel_t self:fifo_file { getattr read write append ioctl lock };
+allow kernel_t self:sock_file { read getattr lock ioctl };
+allow kernel_t self:fd use;
+allow kernel_t proc_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_t:{ lnk_file file } { read getattr lock ioctl };
+allow kernel_t proc_net_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_net_t:file { read getattr lock ioctl };
+allow kernel_t proc_mdstat_t:file { read getattr lock ioctl };
+allow kernel_t proc_kcore_t:file getattr;
+allow kernel_t proc_kmsg_t:file getattr;
+allow kernel_t sysctl_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:file { read getattr lock ioctl };
+allow kernel_t unlabeled_t:fifo_file { getattr read write append ioctl lock };
+	allow kernel_t unlabeled_t:association { sendto recvfrom };
+	allow kernel_t netif_type:netif rawip_send;
+	allow kernel_t netif_type:netif rawip_recv;
+	allow kernel_t node_type:node rawip_send;
+	allow kernel_t node_type:node rawip_recv;
+	allow kernel_t netif_t:netif rawip_send;
+	allow kernel_t netif_type:netif { tcp_send tcp_recv };
+	allow kernel_t node_type:node { tcp_send tcp_recv };
+	allow kernel_t node_t:node rawip_send;
+	allow kernel_t multicast_node_t:node rawip_send;
+	allow kernel_t sysfs_t:dir { read getattr lock search ioctl };
+	allow kernel_t sysfs_t:{ file lnk_file } { read getattr lock ioctl };
+	allow kernel_t usbfs_t:dir search;
+	allow kernel_t filesystem_type:filesystem mount;
+	allow kernel_t security_t:dir { read search getattr };
+	allow kernel_t security_t:file { getattr read write };
+	typeattribute kernel_t can_load_policy;
+	if(!secure_mode_policyload) {
+		allow kernel_t security_t:security load_policy;
+		auditallow kernel_t security_t:security load_policy;
+	}
+	allow kernel_t device_t:dir { read getattr lock search ioctl };
+	allow kernel_t device_t:lnk_file { getattr read };
+	allow kernel_t console_device_t:chr_file { getattr read write append ioctl lock };
+	allow kernel_t bin_t:dir { read getattr lock search ioctl };
+	allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+	allow kernel_t shell_exec_t:file { { read getattr lock execute ioctl } execute_no_trans };
+	allow kernel_t sbin_t:dir { read getattr lock search ioctl };
+	allow kernel_t bin_t:dir { read getattr lock search ioctl };
+	allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+	allow kernel_t bin_t:file { { read getattr lock execute ioctl } execute_no_trans };
+	allow kernel_t domain:process signal;
+	allow kernel_t proc_t:dir search;
+	allow kernel_t domain:dir search;
+	allow kernel_t root_t:dir { read getattr lock search ioctl };
+	allow kernel_t root_t:lnk_file { read getattr lock ioctl };
+	allow kernel_t etc_t:dir { read getattr lock search ioctl };
+	allow kernel_t home_root_t:dir { read getattr lock search ioctl };
+	allow kernel_t usr_t:dir { read getattr lock search ioctl };
+	allow kernel_t usr_t:{ file lnk_file } { read getattr lock ioctl };
+	typeattribute kernel_t mlsprocread;
+	typeattribute kernel_t mlsprocwrite;
+	allow kernel_t self:capability *;
+	allow kernel_t self:fifo_file { create ioctl read getattr lock write setattr append link unlink rename };
+	allow kernel_t self:process transition;
+	allow kernel_t self:file { getattr read write append ioctl lock };
+	allow kernel_t self:nscd *;
+	allow kernel_t self:dbus *;
+	allow kernel_t self:passwd *;
+	allow kernel_t proc_type:{ dir file } *;
+	allow kernel_t sysctl_t:{ dir file } *;
+	allow kernel_t kernel_t:system *;
+	allow kernel_t unlabeled_t:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+	allow kernel_t unlabeled_t:filesystem *;
+	allow kernel_t unlabeled_t:association *;
+	typeattribute kernel_t can_load_kernmodule, can_receive_kernel_messages;
+	typeattribute kernel_t kern_unconfined;
+	allow kernel_t { proc_t proc_net_t }:dir search;
+	allow kernel_t sysctl_type:dir { read getattr lock search ioctl };
+	allow kernel_t sysctl_type:file { { getattr read write append ioctl lock } setattr };
+	allow kernel_t node_type:node *;
+	allow kernel_t netif_type:netif *;
+	allow kernel_t port_type:tcp_socket { send_msg recv_msg name_connect };
+	allow kernel_t port_type:udp_socket { send_msg recv_msg };
+	allow kernel_t port_type:{ tcp_socket udp_socket rawip_socket } name_bind;
+	allow kernel_t node_type:{ tcp_socket udp_socket rawip_socket } node_bind;
+	allow kernel_t unlabeled_t:association { sendto recvfrom };
+	allow kernel_t device_node:{ chr_file blk_file } *;
+	allow kernel_t mtrr_device_t:{ dir file } *;
+	allow kernel_t self:capability sys_rawio;
+	typeattribute kernel_t memory_raw_write, memory_raw_read;
+	typeattribute kernel_t unconfined_domain_type;
+	typeattribute kernel_t can_change_process_identity;
+	typeattribute kernel_t can_change_process_role;
+	typeattribute kernel_t can_change_object_identity;
+	typeattribute kernel_t set_curr_context;
+	allow kernel_t domain:{ { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } socket key_socket } *;
+	allow kernel_t domain:fd use;
+	allow kernel_t domain:fifo_file { getattr read write append ioctl lock };
+	allow kernel_t domain:process ~{ transition dyntransition execmem execstack execheap };
+	allow kernel_t domain:{ sem msgq shm } *;
+	allow kernel_t domain:msg { send receive };
+	allow kernel_t domain:dir { read getattr lock search ioctl };
+	allow kernel_t domain:file { read getattr lock ioctl };
+	allow kernel_t domain:lnk_file { read getattr lock ioctl };
+	dontaudit kernel_t domain:dir { read getattr lock search ioctl };
+	dontaudit kernel_t domain:lnk_file { read getattr lock ioctl };
+	dontaudit kernel_t domain:file { read getattr lock ioctl };
+	dontaudit kernel_t domain:sock_file { read getattr lock ioctl };
+	dontaudit kernel_t domain:fifo_file { read getattr lock ioctl };
+	allow kernel_t file_type:{ file chr_file } ~execmod;
+	allow kernel_t file_type:{ dir lnk_file sock_file fifo_file blk_file } *;
+	allow kernel_t file_type:filesystem *;
+	allow kernel_t file_type:{ unix_stream_socket unix_dgram_socket } name_bind;
+		if (allow_execmod) {
+			allow kernel_t file_type:file execmod;
+		}
+	allow kernel_t filesystem_type:filesystem *;
+	allow kernel_t filesystem_type:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+	allow kernel_t security_t:dir { getattr search read };
+	allow kernel_t security_t:file { getattr read write };
+	typeattribute kernel_t can_load_policy, can_setenforce, can_setsecparam;
+	if(!secure_mode_policyload) {
+		allow kernel_t security_t:security *;
+		auditallow kernel_t security_t:security { load_policy setenforce setbool };
+	}
+		if (allow_execheap) {
+		allow kernel_t self:process execheap;
+		}
+		if (allow_execmem) {
+		allow kernel_t self:process execmem;
+		}
+		if (allow_execmem && allow_execstack) {
+		allow kernel_t self:process execstack;
+		auditallow kernel_t self:process execstack;
+		} else {
+		}
+		if (allow_execheap) {
+		auditallow kernel_t self:process execheap;
+		}
+		if (allow_execmem) {
+		auditallow kernel_t self:process execmem;
+		}
+		if (read_default_t) {
+	allow kernel_t default_t:dir { read getattr lock search ioctl };
+	allow kernel_t default_t:file { read getattr lock ioctl };
+	allow kernel_t default_t:lnk_file { read getattr lock ioctl };
+	allow kernel_t default_t:sock_file { read getattr lock ioctl };
+	allow kernel_t default_t:fifo_file { read getattr lock ioctl };
+		}
+	allow unlabeled_t self:filesystem associate;
+range_transition getty_t login_exec_t s0 - s0:c0.c255;
+range_transition init_t xdm_exec_t s0 - s0:c0.c255;
+range_transition initrc_t crond_exec_t s0 - s0:c0.c255;
+range_transition initrc_t cupsd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t sshd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t udev_exec_t s0 - s0:c0.c255;
+range_transition initrc_t xdm_exec_t s0 - s0:c0.c255;
+range_transition kernel_t udev_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t su_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t initrc_exec_t s0;
+	typeattribute security_t filesystem_type;
+	allow security_t self:filesystem associate;
+	typeattribute security_t mlstrustedobject;
+neverallow ~can_load_policy security_t:security load_policy;
+neverallow ~can_setenforce security_t:security setenforce;
+neverallow ~can_setsecparam security_t:security setsecparam;
+	typeattribute bsdpty_device_t device_node;
+	allow bsdpty_device_t fs_t:filesystem associate;
+	allow bsdpty_device_t tmpfs_t:filesystem associate;
+	allow bsdpty_device_t tmp_t:filesystem associate;
+	typeattribute console_device_t device_node;
+	allow console_device_t fs_t:filesystem associate;
+	allow console_device_t tmpfs_t:filesystem associate;
+	allow console_device_t tmp_t:filesystem associate;
+	allow devpts_t fs_t:filesystem associate;
+	allow devpts_t noxattrfs:filesystem associate;
+	typeattribute devpts_t file_type;
+	typeattribute devpts_t mountpoint;
+	allow devpts_t tmpfs_t:filesystem associate;
+	allow devpts_t tmp_t:filesystem associate;
+	typeattribute devpts_t filesystem_type;
+	allow devpts_t self:filesystem associate;
+	typeattribute devpts_t ttynode, ptynode;
+	typeattribute devtty_t device_node;
+	allow devtty_t fs_t:filesystem associate;
+	allow devtty_t tmpfs_t:filesystem associate;
+	allow devtty_t tmp_t:filesystem associate;
+	typeattribute devtty_t mlstrustedobject;
+	typeattribute ptmx_t device_node;
+	allow ptmx_t fs_t:filesystem associate;
+	allow ptmx_t tmpfs_t:filesystem associate;
+	allow ptmx_t tmp_t:filesystem associate;
+	typeattribute ptmx_t mlstrustedobject;
+	typeattribute tty_device_t device_node;
+	allow tty_device_t fs_t:filesystem associate;
+	allow tty_device_t tmpfs_t:filesystem associate;
+	allow tty_device_t tmp_t:filesystem associate;
+	typeattribute tty_device_t ttynode;
+	typeattribute usbtty_device_t device_node;
+	allow usbtty_device_t fs_t:filesystem associate;
+	allow usbtty_device_t tmpfs_t:filesystem associate;
+	allow usbtty_device_t tmp_t:filesystem associate;
+user system_u roles { system_r } level s0 range s0 - s0:c0.c255;
+user user_u roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+	user root roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+constrain process transition
+	( u1 == u2
+	or t1 == can_change_process_identity
+);
+constrain process transition 
+	( r1 == r2
+	or t1 == can_change_process_role
+);
+constrain process dyntransition
+	( u1 == u2 and r1 == r2 );
+constrain { dir file lnk_file sock_file fifo_file chr_file blk_file } { create relabelto relabelfrom } 
+	( u1 == u2 or t1 == can_change_object_identity );
+constrain { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } { create relabelto relabelfrom } 
+	( u1 == u2 or t1 == can_change_object_identity );
+sid port system_u:object_r:port_t:s0
+sid node system_u:object_r:node_t:s0
+sid netif system_u:object_r:netif_t:s0
+sid devnull system_u:object_r:null_device_t:s0
+sid file system_u:object_r:file_t:s0
+sid fs system_u:object_r:fs_t:s0
+sid kernel system_u:system_r:kernel_t:s0
+sid sysctl system_u:object_r:sysctl_t:s0
+sid unlabeled system_u:object_r:unlabeled_t:s0
+sid any_socket		system_u:object_r:unlabeled_t:s0
+sid file_labels		system_u:object_r:unlabeled_t:s0
+sid icmp_socket		system_u:object_r:unlabeled_t:s0
+sid igmp_packet		system_u:object_r:unlabeled_t:s0
+sid init			system_u:object_r:unlabeled_t:s0
+sid kmod			system_u:object_r:unlabeled_t:s0
+sid netmsg		system_u:object_r:unlabeled_t:s0
+sid policy		system_u:object_r:unlabeled_t:s0
+sid scmp_packet		system_u:object_r:unlabeled_t:s0
+sid sysctl_modprobe 	system_u:object_r:unlabeled_t:s0
+sid sysctl_fs		system_u:object_r:unlabeled_t:s0
+sid sysctl_kernel	system_u:object_r:unlabeled_t:s0
+sid sysctl_net		system_u:object_r:unlabeled_t:s0
+sid sysctl_net_unix	system_u:object_r:unlabeled_t:s0
+sid sysctl_vm		system_u:object_r:unlabeled_t:s0
+sid sysctl_dev		system_u:object_r:unlabeled_t:s0
+sid tcp_socket		system_u:object_r:unlabeled_t:s0
+sid security system_u:object_r:security_t:s0
+fs_use_xattr ext2 system_u:object_r:fs_t:s0;
+fs_use_xattr ext3 system_u:object_r:fs_t:s0;
+fs_use_xattr gfs system_u:object_r:fs_t:s0;
+fs_use_xattr jfs system_u:object_r:fs_t:s0;
+fs_use_xattr reiserfs system_u:object_r:fs_t:s0;
+fs_use_xattr xfs system_u:object_r:fs_t:s0;
+fs_use_task pipefs system_u:object_r:fs_t:s0;
+fs_use_task sockfs system_u:object_r:fs_t:s0;
+fs_use_trans mqueue system_u:object_r:tmpfs_t:s0;
+fs_use_trans shm system_u:object_r:tmpfs_t:s0;
+fs_use_trans tmpfs system_u:object_r:tmpfs_t:s0;
+fs_use_trans devpts system_u:object_r:devpts_t:s0;
+genfscon proc /mtrr system_u:object_r:mtrr_device_t:s0
+genfscon sysfs / system_u:object_r:sysfs_t:s0
+genfscon usbfs / system_u:object_r:usbfs_t:s0
+genfscon usbdevfs / system_u:object_r:usbfs_t:s0
+genfscon rootfs / system_u:object_r:root_t:s0
+genfscon bdev / system_u:object_r:bdev_t:s0
+genfscon binfmt_misc / system_u:object_r:binfmt_misc_fs_t:s0
+genfscon capifs / system_u:object_r:capifs_t:s0
+genfscon configfs / system_u:object_r:configfs_t:s0
+genfscon eventpollfs / system_u:object_r:eventpollfs_t:s0
+genfscon futexfs / system_u:object_r:futexfs_t:s0
+genfscon hugetlbfs / system_u:object_r:hugetlbfs_t:s0
+genfscon inotifyfs / system_u:object_r:inotifyfs_t:s0
+genfscon nfsd / system_u:object_r:nfsd_fs_t:s0
+genfscon ramfs / system_u:object_r:ramfs_t:s0
+genfscon romfs / system_u:object_r:romfs_t:s0
+genfscon cramfs / system_u:object_r:romfs_t:s0
+genfscon rpc_pipefs / system_u:object_r:rpc_pipefs_t:s0
+genfscon autofs / system_u:object_r:autofs_t:s0
+genfscon automount / system_u:object_r:autofs_t:s0
+genfscon cifs / system_u:object_r:cifs_t:s0
+genfscon smbfs / system_u:object_r:cifs_t:s0
+genfscon fat / system_u:object_r:dosfs_t:s0
+genfscon msdos / system_u:object_r:dosfs_t:s0
+genfscon ntfs / system_u:object_r:dosfs_t:s0
+genfscon vfat / system_u:object_r:dosfs_t:s0
+genfscon iso9660 / system_u:object_r:iso9660_t:s0
+genfscon udf / system_u:object_r:iso9660_t:s0
+genfscon nfs / system_u:object_r:nfs_t:s0
+genfscon nfs4 / system_u:object_r:nfs_t:s0
+genfscon afs / system_u:object_r:nfs_t:s0
+genfscon hfsplus / system_u:object_r:nfs_t:s0
+genfscon debugfs / system_u:object_r:debugfs_t:s0
+genfscon proc / system_u:object_r:proc_t:s0
+genfscon proc /sysvipc system_u:object_r:proc_t:s0
+genfscon proc /kmsg system_u:object_r:proc_kmsg_t:s0
+genfscon proc /kcore system_u:object_r:proc_kcore_t:s0
+genfscon proc /mdstat system_u:object_r:proc_mdstat_t:s0
+genfscon proc /net system_u:object_r:proc_net_t:s0
+genfscon proc /xen system_u:object_r:proc_xen_t:s0
+genfscon proc /sys system_u:object_r:sysctl_t:s0
+genfscon proc /irq system_u:object_r:sysctl_irq_t:s0
+genfscon proc /net/rpc system_u:object_r:sysctl_rpc_t:s0
+genfscon proc /sys/fs system_u:object_r:sysctl_fs_t:s0
+genfscon proc /sys/kernel system_u:object_r:sysctl_kernel_t:s0
+genfscon proc /sys/kernel/modprobe system_u:object_r:sysctl_modprobe_t:s0
+genfscon proc /sys/kernel/hotplug system_u:object_r:sysctl_hotplug_t:s0
+genfscon proc /sys/net system_u:object_r:sysctl_net_t:s0
+genfscon proc /sys/net/unix system_u:object_r:sysctl_net_unix_t:s0
+genfscon proc /sys/vm system_u:object_r:sysctl_vm_t:s0
+genfscon proc /sys/dev system_u:object_r:sysctl_dev_t:s0
+genfscon selinuxfs / system_u:object_r:security_t:s0
+portcon udp 7007 system_u:object_r:afs_bos_port_t:s0
+portcon tcp 2040 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7000 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7005 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7004 system_u:object_r:afs_ka_port_t:s0
+portcon udp 7002 system_u:object_r:afs_pt_port_t:s0
+portcon udp 7003 system_u:object_r:afs_vl_port_t:s0
+portcon udp 10080 system_u:object_r:amanda_port_t:s0
+portcon tcp 10080 system_u:object_r:amanda_port_t:s0
+portcon udp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10082 system_u:object_r:amanda_port_t:s0
+portcon tcp 10083 system_u:object_r:amanda_port_t:s0
+portcon tcp 10024 system_u:object_r:amavisd_recv_port_t:s0
+portcon tcp 10025 system_u:object_r:amavisd_send_port_t:s0
+portcon tcp 1720 system_u:object_r:asterisk_port_t:s0
+portcon udp 2427 system_u:object_r:asterisk_port_t:s0
+portcon udp 2727 system_u:object_r:asterisk_port_t:s0
+portcon udp 4569 system_u:object_r:asterisk_port_t:s0
+portcon udp 5060 system_u:object_r:asterisk_port_t:s0
+portcon tcp 113 system_u:object_r:auth_port_t:s0
+portcon tcp 179 system_u:object_r:bgp_port_t:s0
+portcon udp 179 system_u:object_r:bgp_port_t:s0
+portcon tcp 3310 system_u:object_r:clamd_port_t:s0
+portcon udp 4041 system_u:object_r:clockspeed_port_t:s0
+portcon udp 512 system_u:object_r:comsat_port_t:s0
+portcon tcp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 6276 system_u:object_r:dcc_port_t:s0
+portcon udp 6277 system_u:object_r:dcc_port_t:s0
+portcon tcp 1178 system_u:object_r:dbskkd_port_t:s0
+portcon udp 68 system_u:object_r:dhcpc_port_t:s0
+portcon udp 67 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 647 system_u:object_r:dhcpd_port_t:s0
+portcon udp 647 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 847 system_u:object_r:dhcpd_port_t:s0
+portcon udp 847 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 2628 system_u:object_r:dict_port_t:s0
+portcon tcp 3632 system_u:object_r:distccd_port_t:s0
+portcon udp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 79 system_u:object_r:fingerd_port_t:s0
+portcon tcp 20 system_u:object_r:ftp_data_port_t:s0
+portcon tcp 21 system_u:object_r:ftp_port_t:s0
+portcon udp 1718 system_u:object_r:gatekeeper_port_t:s0
+portcon udp 1719 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1721 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 7000 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1213 system_u:object_r:giftd_port_t:s0
+portcon tcp 70 system_u:object_r:gopher_port_t:s0
+portcon udp 70 system_u:object_r:gopher_port_t:s0
+portcon tcp 3128 system_u:object_r:http_cache_port_t:s0
+portcon udp 3130 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8080 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8118 system_u:object_r:http_cache_port_t:s0
+portcon tcp 80 system_u:object_r:http_port_t:s0
+portcon tcp 443 system_u:object_r:http_port_t:s0
+portcon tcp 488 system_u:object_r:http_port_t:s0
+portcon tcp 8008 system_u:object_r:http_port_t:s0
+portcon tcp 9050 system_u:object_r:http_port_t:s0
+portcon tcp 5335 system_u:object_r:howl_port_t:s0
+portcon udp 5353 system_u:object_r:howl_port_t:s0
+portcon tcp 50000 system_u:object_r:hplip_port_t:s0
+portcon tcp 50002 system_u:object_r:hplip_port_t:s0
+portcon tcp 9010 system_u:object_r:i18n_input_port_t:s0
+portcon tcp 5323 system_u:object_r:imaze_port_t:s0
+portcon udp 5323 system_u:object_r:imaze_port_t:s0
+portcon tcp 7 system_u:object_r:inetd_child_port_t:s0
+portcon udp 7 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 9 system_u:object_r:inetd_child_port_t:s0
+portcon udp 9 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 13 system_u:object_r:inetd_child_port_t:s0
+portcon udp 13 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 19 system_u:object_r:inetd_child_port_t:s0
+portcon udp 19 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 37 system_u:object_r:inetd_child_port_t:s0
+portcon udp 37 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 512 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 543 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 544 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 891 system_u:object_r:inetd_child_port_t:s0
+portcon udp 891 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 892 system_u:object_r:inetd_child_port_t:s0
+portcon udp 892 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 2105 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 5666 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 119 system_u:object_r:innd_port_t:s0
+portcon tcp 631 system_u:object_r:ipp_port_t:s0
+portcon udp 631 system_u:object_r:ipp_port_t:s0
+portcon tcp 6667 system_u:object_r:ircd_port_t:s0
+portcon udp 500 system_u:object_r:isakmp_port_t:s0
+portcon tcp 5222 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5223 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5269 system_u:object_r:jabber_interserver_port_t:s0
+portcon tcp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon udp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 749 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon udp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon tcp 88 system_u:object_r:kerberos_port_t:s0
+portcon udp 88 system_u:object_r:kerberos_port_t:s0
+portcon tcp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 517 system_u:object_r:ktalkd_port_t:s0
+portcon udp 518 system_u:object_r:ktalkd_port_t:s0
+portcon tcp 389 system_u:object_r:ldap_port_t:s0
+portcon udp 389 system_u:object_r:ldap_port_t:s0
+portcon tcp 636 system_u:object_r:ldap_port_t:s0
+portcon udp 636 system_u:object_r:ldap_port_t:s0
+portcon tcp 2000 system_u:object_r:mail_port_t:s0
+portcon tcp 1234 system_u:object_r:monopd_port_t:s0
+portcon tcp 3306 system_u:object_r:mysqld_port_t:s0
+portcon tcp 1241 system_u:object_r:nessus_port_t:s0
+portcon udp 137 system_u:object_r:nmbd_port_t:s0
+portcon udp 138 system_u:object_r:nmbd_port_t:s0
+portcon udp 139 system_u:object_r:nmbd_port_t:s0
+portcon udp 123 system_u:object_r:ntp_port_t:s0
+portcon udp 5000 system_u:object_r:openvpn_port_t:s0
+portcon tcp 5988 system_u:object_r:pegasus_http_port_t:s0
+portcon tcp 5989 system_u:object_r:pegasus_https_port_t:s0
+portcon tcp 106 system_u:object_r:pop_port_t:s0
+portcon tcp 109 system_u:object_r:pop_port_t:s0
+portcon tcp 110 system_u:object_r:pop_port_t:s0
+portcon tcp 143 system_u:object_r:pop_port_t:s0
+portcon tcp 220 system_u:object_r:pop_port_t:s0
+portcon tcp 993 system_u:object_r:pop_port_t:s0
+portcon tcp 995 system_u:object_r:pop_port_t:s0
+portcon tcp 1109 system_u:object_r:pop_port_t:s0
+portcon udp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 5432 system_u:object_r:postgresql_port_t:s0
+portcon tcp 60000 system_u:object_r:postgrey_port_t:s0
+portcon tcp 515 system_u:object_r:printer_port_t:s0
+portcon tcp 5703 system_u:object_r:ptal_port_t:s0
+portcon udp 4011 system_u:object_r:pxe_port_t:s0
+portcon udp 24441 system_u:object_r:pyzor_port_t:s0
+portcon udp 1646 system_u:object_r:radacct_port_t:s0
+portcon udp 1813 system_u:object_r:radacct_port_t:s0
+portcon udp 1645 system_u:object_r:radius_port_t:s0
+portcon udp 1812 system_u:object_r:radius_port_t:s0
+portcon tcp 2703 system_u:object_r:razor_port_t:s0
+portcon tcp 513 system_u:object_r:rlogind_port_t:s0
+portcon tcp 953 system_u:object_r:rndc_port_t:s0
+portcon udp 520 system_u:object_r:router_port_t:s0
+portcon tcp 514 system_u:object_r:rsh_port_t:s0
+portcon tcp 873 system_u:object_r:rsync_port_t:s0
+portcon udp 873 system_u:object_r:rsync_port_t:s0
+portcon tcp 137-139 system_u:object_r:smbd_port_t:s0
+portcon tcp 445 system_u:object_r:smbd_port_t:s0
+portcon tcp 25 system_u:object_r:smtp_port_t:s0
+portcon tcp 465 system_u:object_r:smtp_port_t:s0
+portcon tcp 587 system_u:object_r:smtp_port_t:s0
+portcon udp 161 system_u:object_r:snmp_port_t:s0
+portcon udp 162 system_u:object_r:snmp_port_t:s0
+portcon tcp 199 system_u:object_r:snmp_port_t:s0
+portcon tcp 783 system_u:object_r:spamd_port_t:s0
+portcon tcp 22 system_u:object_r:ssh_port_t:s0
+portcon tcp 8000 system_u:object_r:soundd_port_t:s0
+portcon tcp 9433 system_u:object_r:soundd_port_t:s0
+portcon tcp 901 system_u:object_r:swat_port_t:s0
+portcon udp 514 system_u:object_r:syslogd_port_t:s0
+portcon tcp 23 system_u:object_r:telnetd_port_t:s0
+portcon udp 69 system_u:object_r:tftp_port_t:s0
+portcon tcp 8081 system_u:object_r:transproxy_port_t:s0
+portcon tcp 540 system_u:object_r:uucpd_port_t:s0
+portcon tcp 5900 system_u:object_r:vnc_port_t:s0
+portcon tcp 6001 system_u:object_r:xserver_port_t:s0
+portcon tcp 6002 system_u:object_r:xserver_port_t:s0
+portcon tcp 6003 system_u:object_r:xserver_port_t:s0
+portcon tcp 6004 system_u:object_r:xserver_port_t:s0
+portcon tcp 6005 system_u:object_r:xserver_port_t:s0
+portcon tcp 6006 system_u:object_r:xserver_port_t:s0
+portcon tcp 6007 system_u:object_r:xserver_port_t:s0
+portcon tcp 6008 system_u:object_r:xserver_port_t:s0
+portcon tcp 6009 system_u:object_r:xserver_port_t:s0
+portcon tcp 6010 system_u:object_r:xserver_port_t:s0
+portcon tcp 6011 system_u:object_r:xserver_port_t:s0
+portcon tcp 6012 system_u:object_r:xserver_port_t:s0
+portcon tcp 6013 system_u:object_r:xserver_port_t:s0
+portcon tcp 6014 system_u:object_r:xserver_port_t:s0
+portcon tcp 6015 system_u:object_r:xserver_port_t:s0
+portcon tcp 6016 system_u:object_r:xserver_port_t:s0
+portcon tcp 6017 system_u:object_r:xserver_port_t:s0
+portcon tcp 6018 system_u:object_r:xserver_port_t:s0
+portcon tcp 6019 system_u:object_r:xserver_port_t:s0
+portcon tcp 8002 system_u:object_r:xen_port_t:s0
+portcon tcp 2601 system_u:object_r:zebra_port_t:s0
+portcon tcp 8021 system_u:object_r:zope_port_t:s0
+portcon tcp 1-1023 system_u:object_r:reserved_port_t:s0
+portcon udp 1-1023 system_u:object_r:reserved_port_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:compat_ipv4_node_t:s0
+nodecon 0.0.0.0 255.255.255.255 system_u:object_r:inaddr_any_node_t:s0
+nodecon fe80:: ffff:ffff:ffff:ffff:: system_u:object_r:link_local_node_t:s0
+nodecon 127.0.0.1 255.255.255.255 system_u:object_r:lo_node_t:s0
+nodecon ::ffff:0000:0000 ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:mapped_ipv4_node_t:s0
+nodecon ff00:: ff00:: system_u:object_r:multicast_node_t:s0
+nodecon fec0:: ffc0:: system_u:object_r:site_local_node_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system_u:object_r:unspec_node_t:s0
diff --git a/libsepol/tests/policies/test-deps/base-metreq.conf b/libsepol/tests/policies/test-deps/base-metreq.conf
new file mode 100644
index 0000000..bfb4c56
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/base-metreq.conf
@@ -0,0 +1,523 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+
+# Make this decl easy to find
+type base_global_decl_t;
+
+# Actually used in module tests
+type type_req_t;
+attribute attr_req;
+bool bool_req false;
+role role_req_r;
+
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+	require {
+		type base_optional_1, base_optional_2;
+	}
+	allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-deps/base-notmetreq.conf b/libsepol/tests/policies/test-deps/base-notmetreq.conf
new file mode 100644
index 0000000..f2630e7
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/base-notmetreq.conf
@@ -0,0 +1,510 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+	require {
+		type base_optional_1, base_optional_2;
+	}
+	allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-deps/modreq-attr-global.conf b/libsepol/tests/policies/test-deps/modreq-attr-global.conf
new file mode 100644
index 0000000..92f6b30
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-attr-global.conf
@@ -0,0 +1,10 @@
+module modreq_attr_global 1.0;
+
+require { 
+	attribute attr_req;
+}
+
+type mod_global_t;
+
+type new_t, attr_req;
+
diff --git a/libsepol/tests/policies/test-deps/modreq-attr-opt.conf b/libsepol/tests/policies/test-deps/modreq-attr-opt.conf
new file mode 100644
index 0000000..b970c1d
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-attr-opt.conf
@@ -0,0 +1,16 @@
+module modreq_attr_opt 1.0;
+
+require { 
+	class file {read write};
+	
+}
+
+type mod_global_t;
+
+optional {
+	require {
+		attribute attr_req;
+	}
+	type mod_opt_t;
+	type new_t, attr_req;
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-bool-global.conf b/libsepol/tests/policies/test-deps/modreq-bool-global.conf
new file mode 100644
index 0000000..4ef0cc9
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-bool-global.conf
@@ -0,0 +1,15 @@
+module modreq_bool_global 1.0;
+
+require { 
+	bool bool_req;
+	class file { read write };
+}
+
+type mod_global_t;
+
+type a_t;
+type b_t;
+
+if (bool_req) {
+	allow a_t b_t : file { read write };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-bool-opt.conf b/libsepol/tests/policies/test-deps/modreq-bool-opt.conf
new file mode 100644
index 0000000..27af4f2
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-bool-opt.conf
@@ -0,0 +1,22 @@
+module modreq_bool_opt 1.0;
+
+require { 
+	class file {read write};
+	
+}
+
+type mod_global_t;
+
+optional {
+	require {
+		bool bool_req;
+	}
+	
+	type a_t;
+	type b_t;
+	type mod_opt_t;
+
+	if (bool_req) {
+		allow a_t b_t : file { read write };
+	}
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-obj-global.conf b/libsepol/tests/policies/test-deps/modreq-obj-global.conf
new file mode 100644
index 0000000..e9eba77
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-obj-global.conf
@@ -0,0 +1,13 @@
+module modreq_obj_global 1.0;
+
+require { 
+	class sem { create destroy };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+allow mod_foo_t mod_bar_t : sem { create destroy };
+
diff --git a/libsepol/tests/policies/test-deps/modreq-obj-opt.conf b/libsepol/tests/policies/test-deps/modreq-obj-opt.conf
new file mode 100644
index 0000000..67a41a4
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-obj-opt.conf
@@ -0,0 +1,20 @@
+module modreq_obj_global 1.0;
+
+require { 
+	class file { read };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+optional {
+	require {
+		class sem { create destroy };
+	}
+	
+	type mod_opt_t;
+
+	allow mod_foo_t mod_bar_t : sem { create destroy };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-perm-global.conf b/libsepol/tests/policies/test-deps/modreq-perm-global.conf
new file mode 100644
index 0000000..941ca96
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-perm-global.conf
@@ -0,0 +1,10 @@
+module modreq_perm_global 1.0;
+
+require { 
+	class msg { send receive };
+}
+
+type mod_global_t;
+type a_t;
+type b_t;
+allow a_t b_t: msg { send receive };
diff --git a/libsepol/tests/policies/test-deps/modreq-perm-opt.conf b/libsepol/tests/policies/test-deps/modreq-perm-opt.conf
new file mode 100644
index 0000000..43a3f97
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-perm-opt.conf
@@ -0,0 +1,18 @@
+module modreq_perm_opt 1.0;
+
+require { 
+	class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+	require {
+		class msg { send receive };
+	}
+
+	type mod_opt_t;
+	type a_mod_t;
+	type b_mod_t;
+	allow a_mod_t b_mod_t: msg { send receive };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-role-global.conf b/libsepol/tests/policies/test-deps/modreq-role-global.conf
new file mode 100644
index 0000000..01fd3ec
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-role-global.conf
@@ -0,0 +1,13 @@
+module modreq_role_global 1.0;
+
+require { 
+	role role_req_r, user_r;
+}
+
+type mod_global_t;
+
+type a_t;
+
+# role role_req_r types a_t;
+allow role_req_r user_r;
+
diff --git a/libsepol/tests/policies/test-deps/modreq-role-opt.conf b/libsepol/tests/policies/test-deps/modreq-role-opt.conf
new file mode 100644
index 0000000..532a77e
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-role-opt.conf
@@ -0,0 +1,17 @@
+module modreq_role_opt 1.0;
+
+require { 
+	class file {read write};
+	
+}
+
+type mod_global_t;
+
+optional {
+	require {
+		role role_req_r, user_r;
+	}
+	type mod_opt_t;
+
+	allow role_req_r user_r;
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-type-global.conf b/libsepol/tests/policies/test-deps/modreq-type-global.conf
new file mode 100644
index 0000000..e5704a3
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-type-global.conf
@@ -0,0 +1,12 @@
+module modreq_type_global 1.0;
+
+require { 
+	type type_req_t;
+	class file { read write };
+}
+
+type mod_global_t;
+
+type test_t;
+
+allow test_t type_req_t : file { read write };
diff --git a/libsepol/tests/policies/test-deps/modreq-type-opt.conf b/libsepol/tests/policies/test-deps/modreq-type-opt.conf
new file mode 100644
index 0000000..65071d7
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-type-opt.conf
@@ -0,0 +1,16 @@
+module modreq_type_opt 1.0;
+
+require { 
+	type file_t;
+	class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+	require {
+		type type_req_t;
+	}
+	type mod_opt_t;
+	allow type_req_t file_t : file { read write };
+}
\ No newline at end of file
diff --git a/libsepol/tests/policies/test-deps/module.conf b/libsepol/tests/policies/test-deps/module.conf
new file mode 100644
index 0000000..1971e4c
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/module.conf
@@ -0,0 +1,20 @@
+module my_module 1.0;
+
+require { 
+	bool secure_mode;
+	type system_t, sysadm_t, file_t;
+	attribute domain;
+	role system_r;
+	class file {read write};
+	
+}
+
+type new_t, domain;
+role system_r types new_t;
+
+allow system_t file_t : file { read write };
+
+if (secure_mode)
+{
+	allow sysadm_t file_t : file { read write };
+}
diff --git a/libsepol/tests/policies/test-deps/small-base.conf b/libsepol/tests/policies/test-deps/small-base.conf
new file mode 100644
index 0000000..7c1cbe4
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/small-base.conf
@@ -0,0 +1,511 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+	require {
+		type base_optional_1, base_optional_2;
+	}
+	allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/alias-base.conf b/libsepol/tests/policies/test-expander/alias-base.conf
new file mode 100644
index 0000000..4ed46d2
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/alias-base.conf
@@ -0,0 +1,501 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+type enable_optional;
+
+# Alias tests
+type alias_check_1_t;
+type alias_check_2_t;
+type alias_check_3_t;
+
+typealias alias_check_1_t alias alias_check_1_a;
+
+optional {
+	require {
+		type alias_check_2_t;
+	}
+	typealias alias_check_2_t alias alias_check_2_a;
+}
+
+optional {
+	require {
+		type alias_check_3_a;
+	}
+	allow alias_check_3_a enable_optional:file read;
+}
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/alias-module.conf b/libsepol/tests/policies/test-expander/alias-module.conf
new file mode 100644
index 0000000..72d791e
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/alias-module.conf
@@ -0,0 +1,8 @@
+module my_module 1.0;
+
+require { 
+	type alias_check_3_t;
+}
+
+typealias alias_check_3_t alias alias_check_3_a;
+
diff --git a/libsepol/tests/policies/test-expander/base-base-only.conf b/libsepol/tests/policies/test-expander/base-base-only.conf
new file mode 100644
index 0000000..4eae73e
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/base-base-only.conf
@@ -0,0 +1,44 @@
+class security
+class file
+
+sid kernel
+
+common file
+{
+	read
+}
+
+class file
+inherits file
+{
+	entrypoint
+}
+
+class security
+{
+	compute_av
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+dominance { s0 }
+
+category c0;
+
+level s0:c0;
+
+mlsconstrain file { read }
+	( h1 dom h2 );
+')
+
+attribute myattr;
+type mytype_t;
+role myrole_r;
+role myrole_r types mytype_t;
+bool mybool true;
+gen_user(myuser_u,, myrole_r, s0, s0 - s0:c0)
+
+sid kernel	gen_context(myuser_u:myrole_r:mytype_t, s0)
+
+
diff --git a/libsepol/tests/policies/test-expander/module.conf b/libsepol/tests/policies/test-expander/module.conf
new file mode 100644
index 0000000..6186db7
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/module.conf
@@ -0,0 +1,228 @@
+module my_module 1.0;
+
+require { 
+	bool allow_ypbind, secure_mode, allow_execstack;
+	type system_t, sysadm_t;
+	class file {read write};
+	attribute attr_check_base_2, attr_check_base_3;
+	attribute attr_check_base_optional_2;
+}
+
+bool module_1_bool true;
+
+if (module_1_bool && allow_ypbind && secure_mode && allow_execstack) {
+	allow system_t sysadm_t : file { read write };
+}
+
+optional {
+	bool module_1_bool_2 false;
+	require {
+		bool optional_bool_1, optional_bool_2;
+		class file { execute ioctl };
+	}
+	if (optional_bool_1 && optional_bool_2 || module_1_bool_2) {
+		allow system_t sysadm_t : file {execute ioctl};
+	}
+}
+# Type - attribute mapping test
+type module_t;
+attribute attr_check_mod_1;
+attribute attr_check_mod_2;
+attribute attr_check_mod_3;
+attribute attr_check_mod_4;
+attribute attr_check_mod_5;
+attribute attr_check_mod_6;
+attribute attr_check_mod_7;
+attribute attr_check_mod_8;
+attribute attr_check_mod_9;
+attribute attr_check_mod_10;
+attribute attr_check_mod_11;
+optional {
+	require {
+		type base_t;
+	}
+	attribute attr_check_mod_optional_1;
+	attribute attr_check_mod_optional_2;
+	attribute attr_check_mod_optional_3;
+	attribute attr_check_mod_optional_4;
+	attribute attr_check_mod_optional_5;
+	attribute attr_check_mod_optional_6;
+	attribute attr_check_mod_optional_7;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	attribute attr_check_mod_optional_disabled_4;
+	attribute attr_check_mod_optional_disabled_7;
+}
+type attr_check_base_2_1_t, attr_check_base_2;
+type attr_check_base_2_2_t;
+typeattribute attr_check_base_2_2_t attr_check_base_2;
+type attr_check_base_3_3_t, attr_check_base_3;
+type attr_check_base_3_4_t;
+typeattribute attr_check_base_3_4_t attr_check_base_3;
+optional {
+	require {
+		attribute attr_check_base_5;
+	}
+	type attr_check_base_5_1_t, attr_check_base_5;
+	type attr_check_base_5_2_t;
+	typeattribute attr_check_base_5_2_t attr_check_base_5;
+}
+optional {
+	require {
+		attribute attr_check_base_6;
+	}
+	type attr_check_base_6_3_t, attr_check_base_6;
+	type attr_check_base_6_4_t;
+	typeattribute attr_check_base_6_4_t attr_check_base_6;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_base_8;
+	}
+	type attr_check_base_8_1_t, attr_check_base_8;
+	type attr_check_base_8_2_t;
+	typeattribute attr_check_base_8_2_t attr_check_base_8;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_base_9;
+	}
+	type attr_check_base_9_3_t, attr_check_base_9;
+	type attr_check_base_9_4_t;
+	typeattribute attr_check_base_9_4_t attr_check_base_9;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_base_10;
+	}
+	type attr_check_base_10_3_t, attr_check_base_10;
+	type attr_check_base_10_4_t;
+	typeattribute attr_check_base_10_4_t attr_check_base_10;
+}
+optional {
+	require {
+		attribute attr_check_base_11;
+	}
+	type attr_check_base_11_3_t, attr_check_base_11;
+	type attr_check_base_11_4_t;
+	typeattribute attr_check_base_11_4_t attr_check_base_11;
+}
+type attr_check_base_optional_2_1_t, attr_check_base_optional_2;
+type attr_check_base_optional_2_2_t;
+typeattribute attr_check_base_optional_2_2_t attr_check_base_optional_2;
+optional {
+	require {
+		attribute attr_check_base_optional_5;
+	}
+	type attr_check_base_optional_5_1_t, attr_check_base_optional_5;
+	type attr_check_base_optional_5_2_t;
+	typeattribute attr_check_base_optional_5_2_t attr_check_base_optional_5;
+}
+#optional {
+#	require {
+#		attribute attr_check_base_optional_6;
+#	}
+#	type attr_check_base_optional_6_3_t, attr_check_base_optional_6;
+#	type attr_check_base_optional_6_4_t;
+#	typeattribute attr_check_base_optional_6_4_t attr_check_base_optional_6;
+#}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_base_optional_8;
+	}
+	type attr_check_base_optional_8_1_t, attr_check_base_optional_8;
+	type attr_check_base_optional_8_2_t;
+	typeattribute attr_check_base_optional_8_2_t attr_check_base_optional_8;
+}
+type attr_check_mod_2_1_t, attr_check_mod_2;
+type attr_check_mod_2_2_t;
+typeattribute attr_check_mod_2_2_t attr_check_mod_2;
+optional {
+	require {
+		attribute attr_check_mod_5;
+	}
+	type attr_check_mod_5_1_t, attr_check_mod_5;
+	type attr_check_mod_5_2_t;
+	typeattribute attr_check_mod_5_2_t attr_check_mod_5;
+}
+optional {
+	require {
+		attribute attr_check_mod_6;
+	}
+	type attr_check_mod_6_3_t, attr_check_mod_6;
+	type attr_check_mod_6_4_t;
+	typeattribute attr_check_mod_6_4_t attr_check_mod_6;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_mod_8_1_t, attr_check_mod_8;
+	type attr_check_mod_8_2_t;
+	typeattribute attr_check_mod_8_2_t attr_check_mod_8;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_mod_9_3_t, attr_check_mod_9;
+	type attr_check_mod_9_4_t;
+	typeattribute attr_check_mod_9_4_t attr_check_mod_9;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_mod_10_3_t, attr_check_mod_10;
+	type attr_check_mod_10_4_t;
+	typeattribute attr_check_mod_10_4_t attr_check_mod_10;
+}
+optional {
+	require {
+		type base_t;
+	}
+	type attr_check_mod_11_3_t, attr_check_mod_11;
+	type attr_check_mod_11_4_t;
+	typeattribute attr_check_mod_11_4_t attr_check_mod_11;
+}
+#optional {
+#	require {
+#		attribute attr_check_mod_optional_5;
+#	}
+#	type attr_check_mod_optional_5_1_t, attr_check_mod_optional_5;
+#	type attr_check_mod_optional_5_2_t;
+#	typeattribute attr_check_mod_optional_5_2_t attr_check_mod_optional_5;
+#}
+#optional {
+#	require {
+#		attribute attr_check_mod_optional_6;
+#	}
+#	type attr_check_mod_optional_6_3_t, attr_check_mod_optional_6;
+#	type attr_check_mod_optional_6_4_t;
+#	typeattribute attr_check_mod_optional_6_4_t attr_check_mod_optional_6;
+#}
+optional {
+	require {
+		attribute attr_check_base_optional_disabled_5;
+	}
+	type attr_check_base_optional_disabled_5_1_t, attr_check_base_optional_disabled_5;
+	type attr_check_base_optional_disabled_5_2_t;
+	typeattribute attr_check_base_optional_disabled_5_2_t attr_check_base_optional_disabled_5;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_base_optional_disabled_8;
+	}
+	type attr_check_base_optional_disabled_8_1_t, attr_check_base_optional_disabled_8;
+	type attr_check_base_optional_disabled_8_2_t;
+	typeattribute attr_check_base_optional_disabled_8_2_t attr_check_base_optional_disabled_8;
+}
+
diff --git a/libsepol/tests/policies/test-expander/role-base.conf b/libsepol/tests/policies/test-expander/role-base.conf
new file mode 100644
index 0000000..b43389f
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/role-base.conf
@@ -0,0 +1,483 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+# Role mapping test
+type role_check_1_1_t;
+role role_check_1;
+role role_check_1 types role_check_1_1_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/role-module.conf b/libsepol/tests/policies/test-expander/role-module.conf
new file mode 100644
index 0000000..1cc5d22
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/role-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require { 
+	class file {read write};
+	role role_check_1;
+}
+
+type role_check_1_2_t;
+role role_check_1 types role_check_1_2_t;
diff --git a/libsepol/tests/policies/test-expander/small-base.conf b/libsepol/tests/policies/test-expander/small-base.conf
new file mode 100644
index 0000000..7c5d77a
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/small-base.conf
@@ -0,0 +1,721 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+# Type - attribute mapping test
+# Shorthand tests
+# 1 = types in base, 2 = types in mod, 3 = types in both
+# 4 = types in optional in base, 5 = types in optional in mod
+# 6 = types in optional in both
+# 7 = types in disabled optional in base
+# 8 = types in disabled optional in module
+# 9 = types in disabled optional in both
+# 10 = types in enabled optional in base, disabled optional in module
+# 11 = types in disabled optional in base, enabled optional in module
+attribute attr_check_base_1;
+attribute attr_check_base_2;
+attribute attr_check_base_3;
+attribute attr_check_base_4;
+attribute attr_check_base_5;
+attribute attr_check_base_6;
+attribute attr_check_base_7;
+attribute attr_check_base_8;
+attribute attr_check_base_9;
+attribute attr_check_base_10;
+attribute attr_check_base_11;
+optional {
+	require {
+		type module_t;
+	}
+	attribute attr_check_base_optional_1;
+	attribute attr_check_base_optional_2;
+	attribute attr_check_base_optional_3;
+	attribute attr_check_base_optional_4;
+	attribute attr_check_base_optional_5;
+	attribute attr_check_base_optional_6;
+	attribute attr_check_base_optional_8;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	attribute attr_check_base_optional_disabled_5;
+	attribute attr_check_base_optional_disabled_8;
+}
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+	require {
+		type base_optional_1, base_optional_2;
+	}
+	allow base_optional_1 base_optional_2 : file { read write };
+}
+
+# Type - attribute mapping test
+type base_t;
+type attr_check_base_1_1_t, attr_check_base_1;
+type attr_check_base_1_2_t;
+typeattribute attr_check_base_1_2_t attr_check_base_1;
+type attr_check_base_3_1_t, attr_check_base_3;
+type attr_check_base_3_2_t;
+typeattribute attr_check_base_3_2_t attr_check_base_3;
+optional {
+	require {
+		attribute attr_check_base_4;
+	}
+	type attr_check_base_4_1_t, attr_check_base_4;
+	type attr_check_base_4_2_t;
+	typeattribute attr_check_base_4_2_t attr_check_base_4;
+}
+optional {
+	require {
+		type module_t;
+	}
+	type attr_check_base_6_1_t, attr_check_base_6;
+	type attr_check_base_6_2_t;
+	typeattribute attr_check_base_6_2_t attr_check_base_6;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_base_7_1_t, attr_check_base_7;
+	type attr_check_base_7_2_t;
+	typeattribute attr_check_base_7_2_t attr_check_base_7;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_base_9_1_t, attr_check_base_9;
+	type attr_check_base_9_2_t;
+	typeattribute attr_check_base_9_2_t attr_check_base_9;
+}
+optional {
+	require {
+		type module_t;
+	}
+	type attr_check_base_10_1_t, attr_check_base_10;
+	type attr_check_base_10_2_t;
+	typeattribute attr_check_base_10_2_t attr_check_base_10;
+}
+optional {
+	require {
+		type does_not_exist_t;
+	}
+	type attr_check_base_11_1_t, attr_check_base_11;
+	type attr_check_base_11_2_t;
+	typeattribute attr_check_base_11_2_t attr_check_base_11;
+}
+#optional {
+#	require {
+#		attribute attr_check_base_optional_4;
+#	}
+#	type attr_check_base_optional_4_1_t, attr_check_base_optional_4;
+#	type attr_check_base_optional_4_2_t;
+#	typeattribute attr_check_base_optional_4_2_t attr_check_base_optional_4;
+#}
+#optional {
+#	require {
+#		attribute attr_check_base_optional_6;
+#	}
+#	type attr_check_base_optional_6_1_t, attr_check_base_optional_6;
+#	type attr_check_base_optional_6_2_t;
+#	typeattribute attr_check_base_optional_6_2_t attr_check_base_optional_6;
+#}
+optional {
+	require {
+		attribute attr_check_mod_4;
+	}
+	type attr_check_mod_4_1_t, attr_check_mod_4;
+	type attr_check_mod_4_2_t;
+	typeattribute attr_check_mod_4_2_t attr_check_mod_4;
+}
+optional {
+	require {
+		attribute attr_check_mod_6;
+	}
+	type attr_check_mod_6_1_t, attr_check_mod_6;
+	type attr_check_mod_6_2_t;
+	typeattribute attr_check_mod_6_2_t attr_check_mod_6;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_mod_7;
+	}
+	type attr_check_mod_7_1_t, attr_check_mod_7;
+	type attr_check_mod_7_2_t;
+	typeattribute attr_check_mod_7_2_t attr_check_mod_7;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_mod_9;
+	}
+	type attr_check_mod_9_1_t, attr_check_mod_9;
+	type attr_check_mod_9_2_t;
+	typeattribute attr_check_mod_9_2_t attr_check_mod_9;
+}
+optional {
+	require {
+		attribute attr_check_mod_10;
+	}
+	type attr_check_mod_10_1_t, attr_check_mod_10;
+	type attr_check_mod_10_2_t;
+	typeattribute attr_check_mod_10_2_t attr_check_mod_10;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_mod_11;
+	}
+	type attr_check_mod_11_1_t, attr_check_mod_11;
+	type attr_check_mod_11_2_t;
+	typeattribute attr_check_mod_11_2_t attr_check_mod_11;
+}
+optional {
+	require {
+		attribute attr_check_mod_optional_4;
+	}
+	type attr_check_mod_optional_4_1_t, attr_check_mod_optional_4;
+	type attr_check_mod_optional_4_2_t;
+	typeattribute attr_check_mod_optional_4_2_t attr_check_mod_optional_4;
+}
+optional {
+	require {
+		attribute attr_check_mod_optional_6;
+	}
+	type attr_check_mod_optional_6_1_t, attr_check_mod_optional_6;
+	type attr_check_mod_optional_6_2_t;
+	typeattribute attr_check_mod_optional_6_2_t attr_check_mod_optional_6;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_mod_optional_7;
+	}
+	type attr_check_mod_optional_7_1_t, attr_check_mod_optional_7;
+	type attr_check_mod_optional_7_2_t;
+	typeattribute attr_check_mod_optional_7_2_t attr_check_mod_optional_7;
+}
+optional {
+	require {
+		attribute attr_check_mod_optional_disabled_4;
+	}
+	type attr_check_mod_optional_disabled_4_1_t, attr_check_mod_optional_disabled_4;
+	type attr_check_mod_optional_disabled_4_2_t;
+	typeattribute attr_check_mod_optional_disabled_4_2_t attr_check_mod_optional_disabled_4;
+}
+optional {
+	require {
+		type does_not_exist_t;
+		attribute attr_check_mod_optional_disabled_7;
+	}
+	type attr_check_mod_optional_disabled_7_1_t, attr_check_mod_optional_disabled_7;
+	type attr_check_mod_optional_disabled_7_2_t;
+	typeattribute attr_check_mod_optional_disabled_7_2_t attr_check_mod_optional_disabled_7;
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/user-base.conf b/libsepol/tests/policies/test-expander/user-base.conf
new file mode 100644
index 0000000..b60672f
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/user-base.conf
@@ -0,0 +1,487 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+# User mapping test
+type user_check_1_1_t;
+type user_check_1_2_t;
+role user_check_1_1_r;
+role user_check_1_2_r;
+role user_check_1_1_r types user_check_1_1_t;
+role user_check_1_2_r types user_check_1_2_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(user_check_1,, user_check_1_1_r user_check_1_2_r, s0, s0 - s0:c0.c23)
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc /				gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/user-module.conf b/libsepol/tests/policies/test-expander/user-module.conf
new file mode 100644
index 0000000..4ef3e62
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/user-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require { 
+	class file {read write};
+ifdef(`enable_mls',`
+	user user_check_1;
+')
+}
+
diff --git a/libsepol/tests/policies/test-hooks/cmp_policy.conf b/libsepol/tests/policies/test-hooks/cmp_policy.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/cmp_policy.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+	require {
+		type invalid_type;
+	}
+	allow g_b_role_2 g_b_role_3;
+	role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}	
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc /				gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf b/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf
new file mode 100644
index 0000000..c6ecd83
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf
@@ -0,0 +1,15 @@
+module add_symbol_test 1.0;
+
+require { class file { read }; }
+
+role role_a_1;
+role role_a_2;
+role role_t_1;
+role role_t_2;
+
+type type_rt_1;
+
+
+allow role_a_1 role_a_2;
+
+role_transition role_t_1 type_rt_1 role_t_2;
diff --git a/libsepol/tests/policies/test-hooks/module_add_symbols.conf b/libsepol/tests/policies/test-hooks/module_add_symbols.conf
new file mode 100644
index 0000000..cf56e18
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/module_add_symbols.conf
@@ -0,0 +1,12 @@
+module add_symbol_test 1.0;
+
+require { class file { read write }; }
+
+type type_add_1;
+attribute attrib_add_1;
+role role_add_1;
+bool bool_add_1 false;
+
+ifdef(`enable_mls',`',`
+user user_add_1 roles { role_add_1 };
+')
diff --git a/libsepol/tests/policies/test-hooks/small-base.conf b/libsepol/tests/policies/test-hooks/small-base.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/small-base.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+	require {
+		type invalid_type;
+	}
+	allow g_b_role_2 g_b_role_3;
+	role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}	
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc /				gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-linker/module1.conf b/libsepol/tests/policies/test-linker/module1.conf
new file mode 100644
index 0000000..2d5fc31
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/module1.conf
@@ -0,0 +1,145 @@
+module linker_test_1 1.0;
+
+require { 
+	class file { read write };
+	class lnk_file append;
+	role g_b_role_2;
+	attribute g_b_attr_3;
+	attribute g_b_attr_5;
+	attribute o4_b_attr_1;
+	type g_b_type_3;
+}
+
+type tag_g_m1;
+
+#test for type in module and attr in module, added to in module
+attribute g_m1_attr_1;
+type g_m1_type_1, g_m1_attr_1;
+type g_m1_type_2;
+typeattribute g_m1_type_2 g_m1_attr_1;
+
+#add role in module test
+role g_m1_role_1;
+role g_m1_role_1 types g_m1_type_1;
+
+# test for attr declared in base, added to in module
+type g_m1_type_3;
+typeattribute g_m1_type_3 g_b_attr_3;
+
+# test for attr declared in base, added to in 2 modules
+type g_m1_type_4;
+typeattribute g_m1_type_4 g_b_attr_5;
+
+# test for attr declared in base optional, added to in module
+type g_m1_type_5;
+typeattribute g_m1_type_5 o4_b_attr_1;
+
+# test for attr declared in module, added to in base optional
+attribute g_m1_attr_2;
+
+#add type to base role test
+role g_b_role_2 types g_m1_type_1;
+role g_b_role_3;
+role g_b_role_3 types g_m1_type_2;
+
+#add type to base optional role test
+role o1_b_role_2;
+role o1_b_role_2 types g_m1_type_1;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1;
+role o4_b_role_1 types g_m1_type_2;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+attribute g_m1_attr_3;
+type g_m1_type_6, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module , added to in other module optional
+attribute g_m1_attr_4;
+type g_m1_type_7, g_m1_attr_4;
+
+# alias tests
+typealias g_b_type_3 alias g_m_alias_1;
+
+# single boolean in module
+bool g_m1_bool_1 true;
+if (g_m1_bool_1) {
+	allow g_m1_type_1 g_m1_type_2 : lnk_file append;
+}
+
+
+optional {
+	require {
+		type optional_type;
+		attribute g_b_attr_4;
+		attribute o1_b_attr_2;
+		class lnk_file { ioctl };
+	}
+
+	type tag_o1_m1;
+
+	attribute o1_m1_attr_1;
+	type o1_m1_type_2, o1_m1_attr_1;
+	
+	type o1_m1_type_1;
+	role o1_m1_role_1;
+	role o1_m1_role_1 types o1_m1_type_1;
+
+	type o1_m1_type_3;
+	typeattribute o1_m1_type_3 g_b_attr_4;
+
+	type o1_m1_type_5;
+	typeattribute o1_m1_type_5 o1_b_attr_2;	
+
+	bool o1_m1_bool_1 false;
+	if (o1_m1_bool_1) {
+		allow o1_m1_type_2 o1_m1_type_1 : lnk_file ioctl;
+	}
+	
+}
+
+optional {
+	require {
+		type optional_type;
+		#role g_b_role_4; // This causes a bug where the role scope doesn't get copied into base
+	}
+	
+	type tag_o2_m1;
+
+	role g_b_role_4;
+	role g_b_role_4 types g_m1_type_2;
+}
+
+optional {
+	require {
+		attribute g_b_attr_6;
+	}
+
+	type tag_o3_m1;
+
+	type o3_m1_type_1;	
+	role o3_b_role_1;
+        role o3_b_role_1 types o3_m1_type_1;
+
+	type o3_m1_type_2, g_b_attr_6;
+
+	attribute o3_m1_attr_1;	
+
+	# attr a added to in base optional, declared/added in module optional, added to in other module
+	attribute o3_m1_attr_2;
+	type o3_m1_type_3, o3_m1_attr_2;
+
+}
+
+optional {
+	require {
+		type enable_optional;
+	}
+	type tag_o4_m1;
+
+	attribute o4_m1_attr_1;
+	type o4_m1_type_1;
+	typeattribute o4_m1_type_1 o4_m1_attr_1;
+
+
+}
diff --git a/libsepol/tests/policies/test-linker/module2.conf b/libsepol/tests/policies/test-linker/module2.conf
new file mode 100644
index 0000000..7a31109
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/module2.conf
@@ -0,0 +1,66 @@
+module linker_test_2 1.0;
+
+require { 
+	class file { read write };
+	class lnk_file { unlink };
+	attribute g_b_attr_5;
+	attribute g_b_attr_6;
+	attribute g_m1_attr_3;
+	attribute o3_m1_attr_2;
+}
+
+type tag_g_m2;
+
+type g_m2_type_1;
+role g_m2_role_1;
+role g_m2_role_1 types g_m2_type_1;
+
+type g_m2_type_4, g_b_attr_5;
+type g_m2_type_5, g_b_attr_6;
+
+#add types to role declared in base test
+type g_m2_type_2;
+role g_b_role_3;
+role g_b_role_3 types g_m2_type_2;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1;
+role o4_b_role_1 types g_m2_type_1;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+type g_m2_type_3, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module optional, added to in other module
+type g_m2_type_6, o3_m1_attr_2;
+
+# cond mapping tests
+bool g_m2_bool_1 true;
+bool g_m2_bool_2 false;
+if (g_m2_bool_1 && g_m2_bool_2) {
+	allow g_m2_type_1 g_m2_type_2 : lnk_file unlink;
+}
+
+optional {
+	require {
+		type optional_type;
+	}
+
+	type tag_o1_m2;
+
+	type o1_m2_type_1;
+	role o1_m2_role_1;
+	role o1_m2_role_1 types o1_m2_type_1;
+}
+
+
+optional {
+	require {
+		attribute g_m1_attr_4;
+		attribute o4_m1_attr_1;
+	}
+	type tag_o2_m2;
+
+	type o2_m2_type_1, g_m1_attr_4;
+	type o2_m2_type_2, o4_m1_attr_1;
+
+}
diff --git a/libsepol/tests/policies/test-linker/small-base.conf b/libsepol/tests/policies/test-linker/small-base.conf
new file mode 100644
index 0000000..3a66f91
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/small-base.conf
@@ -0,0 +1,600 @@
+# FLASK
+
+#
+# Define the security object classes 
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers 
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+	unlink
+	link
+	rename
+	execute
+	swapon
+	quotaon
+	mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+	ioctl
+	read
+	write
+	create
+	getattr
+	setattr
+	lock
+	relabelfrom
+	relabelto
+	append
+# socket-specific
+	bind
+	connect
+	listen
+	accept
+	getopt
+	setopt
+	shutdown
+	recvfrom
+	sendto
+	recv_msg
+	send_msg
+	name_bind
+}	
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+	create
+	destroy
+	getattr
+	setattr
+	read
+	write
+	associate
+	unix_read
+	unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+	mount
+	remount
+	unmount
+	getattr
+	relabelfrom
+	relabelto
+	transition
+	associate
+	quotamod
+	quotaget
+}
+
+class dir
+inherits file
+{
+	add_name
+	remove_name
+	reparent
+	search
+	rmdir
+}
+
+class file
+inherits file
+{
+	execute_no_trans
+	entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+	use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node 
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+	enforce_dest
+}
+
+class netif
+{
+	tcp_recv
+	tcp_send
+	udp_recv
+	udp_send
+	rawip_recv
+	rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+	connectto
+	newconn
+	acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+	fork
+	transition
+	sigchld # commonly granted from child to parent
+	sigkill # cannot be caught or ignored
+	sigstop # cannot be caught or ignored
+	signull # for kill(pid, 0)
+	signal  # all other signals
+	ptrace
+	getsched
+	setsched
+	getsession
+	getpgid
+	setpgid
+	getcap
+	setcap
+	share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+	enqueue
+}
+
+class msg
+{
+	send
+	receive
+}
+
+class shm
+inherits ipc
+{
+	lock
+}
+
+
+#
+# Define the access vector interpretation for the security server. 
+#
+
+class security
+{
+	compute_av
+	transition_sid
+	member_sid
+	sid_to_context
+	context_to_sid
+	load_policy
+	get_sids
+	change_sid
+	get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+	ipc_info
+	avc_toggle
+	nfsd_control
+	bdflush
+	syslog_read
+	syslog_mod
+	syslog_console
+	ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+	# The capabilities are defined in include/linux/capability.h
+	# Care should be taken to ensure that these are consistent with
+	# those definitions. (Order matters)
+
+	chown           
+	dac_override    
+	dac_read_search 
+	fowner          
+	fsetid          
+	kill            
+	setgid           
+	setuid           
+	setpcap          
+	linux_immutable  
+	net_bind_service 
+	net_broadcast    
+	net_admin        
+	net_raw          
+	ipc_lock         
+	ipc_owner        
+	sys_module       
+	sys_rawio        
+	sys_chroot       
+	sys_ptrace       
+	sys_pacct        
+	sys_admin        
+	sys_boot         
+	sys_nice         
+	sys_resource     
+	sys_time         
+	sys_tty_config  
+	mknod
+	lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+	( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type enable_optional;
+
+#decorative type for finding this decl, every block should have one
+type tag_g_b;
+
+attribute g_b_attr_1;
+attribute g_b_attr_2;
+attribute g_b_attr_3;
+attribute g_b_attr_4;
+attribute g_b_attr_5;
+attribute g_b_attr_6;
+
+type g_b_type_1, g_b_attr_1;
+type g_b_type_2, g_b_attr_2;
+type g_b_type_3;
+
+role g_b_role_1;
+role g_b_role_2;
+role g_b_role_3;
+role g_b_role_4;
+role g_b_role_1 types g_b_type_1;
+role g_b_role_2 types g_b_type_2;
+role g_b_role_3 types g_b_type_2;
+role g_b_role_4 types g_b_type_2;
+
+bool g_b_bool_1 false;
+bool g_b_bool_2 true;
+
+allow g_b_type_1 g_b_type_2 : security { compute_av load_policy };
+allow g_b_type_1 g_b_type_2 : file *; # test *
+allow g_b_type_1 g_b_type_2 : process ~ptrace; #test ~
+
+typealias g_b_type_3 alias g_b_alias_1;
+
+if (g_b_bool_1) {
+	allow g_b_type_1 g_b_type_2: lnk_file read;
+}
+
+
+optional {
+	require {
+		type enable_optional;
+		attribute g_m1_attr_2;
+	}
+	type tag_o1_b;
+
+	attribute o1_b_attr_1;
+	type o1_b_type_1, o1_b_attr_1;
+	bool o1_b_bool_1 true;
+	role o1_b_role_1;
+	role o1_b_role_1 types o1_b_type_1;
+	role o1_b_role_2;
+	role o1_b_role_2 types o1_b_type_1;
+
+	attribute o1_b_attr_2;
+
+	type o1_b_type_2, g_m1_attr_2;
+
+	if (o1_b_bool_1) {
+		allow o1_b_type_1 o1_b_type_2: lnk_file write;
+	}
+	
+}
+
+optional {
+	require {
+		# this should be activated by module 1
+		type g_m1_type_1;
+		attribute o3_m1_attr_2;
+	}	
+	type tag_o2_b;	
+
+	type o2_b_type_1, o3_m1_attr_2;
+}
+
+optional {
+	require {
+		#this block should not come on
+		type invalid_type;
+	}
+	type tag_o3_b;
+
+
+	attribute o3_b_attr_1;
+	type o3_b_type_1;
+	bool o3_b_bool_1 true;
+
+	role o3_b_role_1;
+	role o3_b_role_1 types o3_b_type_1;
+
+	allow g_b_type_1 invalid_type : sem { create destroy };
+}
+
+optional {
+	require {
+		# also should be enabled by module 1
+		type enable_optional;
+		type g_m1_type_1;
+		attribute o3_m1_attr_1;
+		attribute g_m1_attr_3;
+	}
+	
+	type tag_o4_b;
+
+	attribute o4_b_attr_1;
+
+	role o4_b_role_1;
+	role o4_b_role_1 types g_m1_type_1;
+
+	# test for attr declared in module optional, added to in base optional
+	type o4_b_type_1, o3_m1_attr_1;
+
+	type o4_b_type_2, g_m1_attr_3;
+}
+
+optional {
+	require {
+		attribute g_m1_attr_4;
+		attribute o4_m1_attr_1;
+	}
+	type tag_o5_b;
+
+	type o5_b_type_1, g_m1_attr_4;
+	type o5_b_type_2, o4_m1_attr_1;
+}
+
+optional {
+	require {
+		type enable_optional;
+	}
+	type tag_o6_b;
+
+	typealias g_b_type_3 alias g_b_alias_2;
+}
+
+optional {
+	require {
+		type g_m_alias_1;
+	}
+	type tag_o7_b;
+
+	allow g_m_alias_1 enable_optional:file read;
+}
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+gen_user(g_b_user_2,, g_b_role_1, s0, s0 - s0:c0, c1, c3, c4, c5)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel	gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc /				gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/test-common.c b/libsepol/tests/test-common.c
new file mode 100644
index 0000000..058b743
--- /dev/null
+++ b/libsepol/tests/test-common.c
@@ -0,0 +1,262 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *         Chad Sellers <csellers@tresys.com>
+ *         Chris PeBenito <cpebenito@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
+ */
+
+/* This has tests that are common between test suites*/
+
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len)
+{
+	scope_datum_t *scope;
+	int found;
+	unsigned int i, j;
+	/* make sure it is in global symtab */
+	if (!hashtab_search(p->symtab[sym_type].table, id)) {
+		fprintf(stderr, "symbol %s not found in table %d\n", id, sym_type);
+		CU_FAIL_FATAL();
+	}
+	/* make sure its scope is correct */
+	scope = hashtab_search(p->scope[sym_type].table, id);
+	CU_ASSERT_FATAL(scope != NULL);
+	CU_ASSERT(scope->scope == scope_type);
+	CU_ASSERT(scope->decl_ids_len == len);
+	if (scope->decl_ids_len != len)
+		fprintf(stderr, "sym %s has %d decls, %d expected\n", id, scope->decl_ids_len, len);
+	for (i = 0; i < len; i++) {
+		found = 0;
+		for (j = 0; j < len; j++) {
+			if (decls[i] == scope->decl_ids[j])
+				found++;
+		}
+		CU_ASSERT(found == 1);
+	}
+
+}
+
+static int common_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	common_datum_t *d = (common_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_COMMONS][d->s.value - 1] == (char *)key);
+	return 0;
+}
+
+static int class_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	class_datum_t *d = (class_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_CLASSES][d->s.value - 1] == (char *)key);
+	CU_ASSERT(p->class_val_to_struct[d->s.value - 1] == d);
+	return 0;
+}
+
+static int role_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	role_datum_t *d = (role_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_ROLES][d->s.value - 1] == (char *)key);
+	CU_ASSERT(p->role_val_to_struct[d->s.value - 1] == d);
+	return 0;
+}
+
+static int type_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	type_datum_t *d = (type_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	if (!d->primary)
+		return 0;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_TYPES][d->s.value - 1] == (char *)key);
+	CU_ASSERT(p->type_val_to_struct[d->s.value - 1] == d);
+
+	return 0;
+}
+
+static int user_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	user_datum_t *d = (user_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_USERS][d->s.value - 1] == (char *)key);
+	CU_ASSERT(p->user_val_to_struct[d->s.value - 1] == d);
+	return 0;
+}
+
+static int cond_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	cond_bool_datum_t *d = (cond_bool_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_BOOLS][d->s.value - 1] == (char *)key);
+	CU_ASSERT(p->bool_val_to_struct[d->s.value - 1] == d);
+	return 0;
+}
+
+static int level_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	level_datum_t *d = (level_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_LEVELS][d->level->sens - 1] == (char *)key);
+	return 0;
+}
+
+static int cat_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	cat_datum_t *d = (cat_datum_t *) datum;
+	policydb_t *p = (policydb_t *) data;
+
+	CU_ASSERT(p->sym_val_to_name[SYM_CATS][d->s.value - 1] == (char *)key);
+	return 0;
+}
+
+static int (*test_index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *p) = {
+common_test_index, class_test_index, role_test_index, type_test_index, user_test_index, cond_test_index, level_test_index, cat_test_index,};
+
+void test_policydb_indexes(policydb_t * p)
+{
+	int i;
+
+	for (i = 0; i < SYM_NUM; i++) {
+		hashtab_map(p->symtab[i].table, test_index_f[i], p);
+	}
+}
+
+void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor)
+{
+	type_datum_t *type, *primary;
+	unsigned int my_primary, my_flavor, my_value;
+
+	type = hashtab_search(p->p_types.table, id);
+	primary = hashtab_search(p->p_types.table, primary_id);
+
+	CU_ASSERT_PTR_NOT_NULL(type);
+	CU_ASSERT_PTR_NOT_NULL(primary);
+
+	if (type && primary) {
+		if (mode) {
+			my_flavor = type->flavor;
+		} else {
+			my_flavor = flavor;
+		}
+
+		if (my_flavor == TYPE_TYPE) {
+			my_primary = 0;
+			my_value = primary->s.value;
+		} else if (my_flavor == TYPE_ALIAS) {
+			my_primary = primary->s.value;
+			CU_ASSERT_NOT_EQUAL(type->s.value, primary->s.value);
+			my_value = type->s.value;
+		} else {
+			CU_FAIL("not an alias");
+		}
+
+		CU_ASSERT(type->primary == my_primary);
+		CU_ASSERT(type->flavor == my_flavor);
+		CU_ASSERT(type->s.value == my_value);
+	}
+}
+
+role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags)
+{
+	ebitmap_node_t *tnode;
+	unsigned int i, j, new, found = 0;
+	role_datum_t *role;
+
+	if (decl)
+		role = hashtab_search(decl->p_roles.table, id);
+	else
+		role = hashtab_search(p->p_roles.table, id);
+
+	if (!role)
+		printf("role %s can't be found! \n", id);
+
+	CU_ASSERT_FATAL(role != NULL);
+
+	ebitmap_for_each_bit(&role->types.types, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			new = 0;
+			for (j = 0; j < len; j++) {
+				if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+					found++;
+					new = 1;
+				}
+			}
+			if (new == 0) {
+				printf("\nRole %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+			}
+			CU_ASSERT(new == 1);
+		}
+	}
+	CU_ASSERT(found == len);
+	if (found != len)
+		printf("\nrole %s has %d types, %d expected\n", p->sym_val_to_name[SYM_ROLES][role->s.value - 1], found, len);
+	/* roles should never have anything in the negset */
+	CU_ASSERT(role->types.negset.highbit == 0);
+	CU_ASSERT(role->types.flags == flags);
+
+	return role;
+}
+
+void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len)
+{
+	ebitmap_node_t *tnode;
+	int j, new, found = 0;
+	unsigned int i;
+	type_datum_t *attr;
+
+	if (decl)
+		attr = hashtab_search(decl->p_types.table, id);
+	else
+		attr = hashtab_search(p->p_types.table, id);
+
+	if (attr == NULL)
+		printf("could not find attr %s in decl %d\n", id, decl->decl_id);
+	CU_ASSERT_FATAL(attr != NULL);
+	CU_ASSERT(attr->flavor == TYPE_ATTRIB);
+	CU_ASSERT(attr->primary == 1);
+
+	ebitmap_for_each_bit(&attr->types, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			new = 0;
+			for (j = 0; j < len; j++) {
+				if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+					found++;
+					new = 1;
+				}
+			}
+			if (new == 0) {
+				printf("\nattr %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+			}
+			CU_ASSERT(new == 1);
+		}
+	}
+	CU_ASSERT(found == len);
+	if (found != len)
+		printf("\nattr %s has %d types, %d expected\n", id, found, len);
+}
diff --git a/libsepol/tests/test-common.h b/libsepol/tests/test-common.h
new file mode 100644
index 0000000..5a1e650
--- /dev/null
+++ b/libsepol/tests/test-common.h
@@ -0,0 +1,78 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *         Chad Sellers <csellers@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
+ */
+
+#ifndef __TEST_COMMON_H__
+#define __TEST_COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+
+/* p		the policy being inspected
+ * id		string symbol identifier
+ * sym_type	symbol type (eg., SYM_ROLES, SYM_TYPES)
+ * scope_type	what scope the role should have (eg., SCOPE_DECL or SCOPE_REQ)
+ * decls	integer array of decl id's that we expect the role to have in the scope table
+ * len		number of elements in decls
+ * 
+ * This is a utility function to test for the symbol's presence in the global symbol table, 
+ * the scope table, and that the decl blocks we think this symbol is in are correct
+ */
+extern void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len);
+
+/* Test the indexes in the policydb to ensure their correctness. These include
+ * the sym_val_to_name[], class_val_to_struct, role_val_to_struct, type_val_to_struct,
+ * user_val_to_struct, and bool_val_to_struct indexes.
+ */
+extern void test_policydb_indexes(policydb_t * p);
+
+/* Test alias datum to ensure that it is as expected
+ *
+ * id = the key for the alias
+ * primary_id = the key for its primary
+ * mode: 0 = test the datum according to the flavor value in the call
+         1 = automatically detect the flavor value and test the datum accordingly
+ * flavor = flavor value if in mode 0
+ */
+extern void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor);
+
+/* p		the policy being inspected
+ * id		string role identifier
+ * decl		the decl block which we are looking in for the role datum
+ * types	the array of string types which we expect the role has in its type ebitmap
+ * len		number of elements in types
+ * flags	the expected flags in the role typeset (eg., * or ~)
+ *
+ * This is a utility function to test whether the type set associated with a role in a specific
+ * avrule decl block matches our expectations
+ */
+extern role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags);
+
+/* p		the policy being inspected
+ * id		string attribute identifier
+ * decl		the decl block which we are looking in for the attribute datum
+ * types	the array of string types which we expect the attribute has in its type ebitmap
+ * len		number of elements in types
+ *
+ * This is a utility function to test whether the type set associated with an attribute in a specific
+ * avrule decl block matches our expectations 
+ */
+extern void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len);
+
+#endif
diff --git a/libsepol/tests/test-cond.c b/libsepol/tests/test-cond.c
new file mode 100644
index 0000000..32bf6f1
--- /dev/null
+++ b/libsepol/tests/test-cond.c
@@ -0,0 +1,95 @@
+/*
+ * 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 "test-cond.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+
+static policydb_t basemod;
+static policydb_t base_expanded;
+
+int cond_test_init(void)
+{
+	if (policydb_init(&base_expanded)) {
+		fprintf(stderr, "out of memory!\n");
+		policydb_destroy(&basemod);
+		return -1;
+	}
+
+	if (test_load_policy(&basemod, POLICY_BASE, 1, "test-cond", "refpolicy-base.conf"))
+		goto cleanup;
+
+	if (link_modules(NULL, &basemod, NULL, 0, 0)) {
+		fprintf(stderr, "link modules failed\n");
+		goto cleanup;
+	}
+
+	if (expand_module(NULL, &basemod, &base_expanded, 0, 1)) {
+		fprintf(stderr, "expand module failed\n");
+		goto cleanup;
+	}
+
+	return 0;
+
+      cleanup:
+	policydb_destroy(&basemod);
+	policydb_destroy(&base_expanded);
+	return -1;
+}
+
+int cond_test_cleanup(void)
+{
+	policydb_destroy(&basemod);
+	policydb_destroy(&base_expanded);
+
+	return 0;
+}
+
+static void test_cond_expr_equal(void)
+{
+	cond_node_t *a, *b;
+
+	a = base_expanded.cond_list;
+	while (a) {
+		b = base_expanded.cond_list;
+		while (b) {
+			if (a == b) {
+				CU_ASSERT(cond_expr_equal(a, b));
+			} else {
+				CU_ASSERT(cond_expr_equal(a, b) == 0);
+			}
+			b = b->next;
+		}
+		a = a->next;
+	}
+}
+
+int cond_add_tests(CU_pSuite suite)
+{
+	if (NULL == CU_add_test(suite, "cond_expr_equal", test_cond_expr_equal)) {
+		return CU_get_error();
+	}
+	return 0;
+}
diff --git a/libsepol/tests/test-cond.h b/libsepol/tests/test-cond.h
new file mode 100644
index 0000000..702d9e0
--- /dev/null
+++ b/libsepol/tests/test-cond.h
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#ifndef __TEST_COND_H__
+#define __TEST_COND_H__
+
+#include <CUnit/Basic.h>
+
+int cond_test_init(void);
+int cond_test_cleanup(void);
+int cond_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-deps.c b/libsepol/tests/test-deps.c
new file mode 100644
index 0000000..e7d2beb
--- /dev/null
+++ b/libsepol/tests/test-deps.c
@@ -0,0 +1,302 @@
+/*
+ * 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 "test-deps.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <stdlib.h>
+
+/* Tests for dependency checking / handling, specifically:
+ *
+ * 1 type in module global.
+ * 2 attribute in module global.
+ * 3 object class / perm in module global.
+ * 4 boolean in module global.
+ * 5 role in module global.
+ *
+ * 6 type in module optional.
+ * 7 attribute in module optional.
+ * 8 object class / perm in module optional.
+ * 9 boolean in module optional.
+ * 10 role in module optional.
+ *
+ * 11 type in base optional.
+ * 12 attribute in base optional.
+ * 13 object class / perm in base optional.
+ * 14 boolean in base optional.
+ * 15 role in base optional.
+ *
+ * Each of these tests are done with the dependency met and not
+ * met. Additionally, each of the required symbols is used in the
+ * scope it is required.
+ *
+ * In addition to the simple tests, we have test with more complex
+ * modules that test:
+ *
+ * 17 mutual dependencies between two modules.
+ * 18 circular dependency between three modules.
+ * 19 large number of dependencies in a module with a more complex base.
+ * 20 nested optionals with requires.
+ *
+ * Again, each of these tests is done with the requirements met and not
+ * met.
+ */
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+
+#define BASE_MODREQ_TYPE_GLOBAL    0
+#define BASE_MODREQ_ATTR_GLOBAL    1
+#define BASE_MODREQ_OBJ_GLOBAL     2
+#define BASE_MODREQ_BOOL_GLOBAL    3
+#define BASE_MODREQ_ROLE_GLOBAL    4
+#define BASE_MODREQ_PERM_GLOBAL    5
+#define BASE_MODREQ_TYPE_OPT       6
+#define BASE_MODREQ_ATTR_OPT       7
+#define BASE_MODREQ_OBJ_OPT        8
+#define BASE_MODREQ_BOOL_OPT       9
+#define BASE_MODREQ_ROLE_OPT       10
+#define BASE_MODREQ_PERM_OPT       11
+#define NUM_BASES                  12
+
+static policydb_t bases_met[NUM_BASES];
+static policydb_t bases_notmet[NUM_BASES];
+
+extern int mls;
+
+int deps_test_init(void)
+{
+	int i;
+
+	/* To test linking we need 1 base per link test and in
+	 * order to load them in the init function we have
+	 * to keep them all around. Not ideal, but it shouldn't
+	 * matter too much.
+	 */
+	for (i = 0; i < NUM_BASES; i++) {
+		if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
+			return -1;
+	}
+
+	for (i = 0; i < NUM_BASES; i++) {
+		if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
+			return -1;
+	}
+
+	return 0;
+}
+
+int deps_test_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_BASES; i++) {
+		policydb_destroy(&bases_met[i]);
+	}
+
+	for (i = 0; i < NUM_BASES; i++) {
+		policydb_destroy(&bases_notmet[i]);
+	}
+
+	return 0;
+}
+
+/* This function performs testing of the dependency handles for module global
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ *  req_met            boolean indicating whether the base policy meets the
+ *                       requirements for the modules global block.
+ *  b                  index of the base policy in the global bases_met array.
+ *
+ *  policy             name of the policy module to load for this test.
+ *  decl_type          name of the unique type found in the module's global
+ *                       section is to find that avrule_decl.
+ */
+static void do_deps_modreq_global(int req_met, int b, char *policy, char *decl_type)
+{
+	policydb_t *base;
+	policydb_t mod;
+	policydb_t *mods[] = { &mod };
+	avrule_decl_t *decl;
+	int ret, link_ret;
+	sepol_handle_t *h;
+
+	/* suppress error reporting - this is because we know that we
+	 * are going to get errors and don't want libsepol complaining
+	 * about it constantly. */
+	h = sepol_handle_create();
+	CU_ASSERT_FATAL(h != NULL);
+	sepol_msg_set_callback(h, NULL, NULL);
+
+	if (req_met) {
+		base = &bases_met[b];
+		link_ret = 0;
+	} else {
+		base = &bases_notmet[b];
+		link_ret = -3;
+	}
+
+	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+	/* link the modules and check for the correct return value.
+	 */
+	ret = link_modules(h, base, mods, 1, 0);
+	CU_ASSERT_FATAL(ret == link_ret);
+	policydb_destroy(&mod);
+
+	if (!req_met)
+		return;
+
+	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+	CU_ASSERT_FATAL(decl != NULL);
+
+	CU_ASSERT(decl->enabled == 1);
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 1 - 5 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_global(void)
+{
+	/* object classes */
+	do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+	/* types */
+	do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+	/* attributes */
+	do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+	/* booleans */
+	do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+	/* roles */
+	do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+	do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+	do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+}
+
+/* This function performs testing of the dependency handles for module optional
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ *  req_met            boolean indicating whether the base policy meets the
+ *                       requirements for the modules global block.
+ *  b                  index of the base policy in the global bases_met array.
+ *
+ *  policy             name of the policy module to load for this test.
+ *  decl_type          name of the unique type found in the module's global
+ *                       section is to find that avrule_decl.
+ */
+static void do_deps_modreq_opt(int req_met, int ret_val, int b, char *policy, char *decl_type)
+{
+	policydb_t *base;
+	policydb_t mod;
+	policydb_t *mods[] = { &mod };
+	avrule_decl_t *decl;
+	int ret;
+	sepol_handle_t *h;
+
+	/* suppress error reporting - this is because we know that we
+	 * are going to get errors and don't want libsepol complaining
+	 * about it constantly. */
+	h = sepol_handle_create();
+	CU_ASSERT_FATAL(h != NULL);
+	sepol_msg_set_callback(h, NULL, NULL);
+
+	if (req_met) {
+		base = &bases_met[b];
+	} else {
+		base = &bases_notmet[b];
+	}
+
+	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+	/* link the modules and check for the correct return value.
+	 */
+	ret = link_modules(h, base, mods, 1, 0);
+	CU_ASSERT_FATAL(ret == ret_val);
+	policydb_destroy(&mod);
+	if (ret_val < 0)
+		return;
+
+	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+	CU_ASSERT_FATAL(decl != NULL);
+
+	if (req_met) {
+		CU_ASSERT(decl->enabled == 1);
+	} else {
+		CU_ASSERT(decl->enabled == 0);
+	}
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 6 - 10 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_opt(void)
+{
+	/* object classes */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+	/* types */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+	/* attributes */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+	/* booleans */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+	/* roles */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+	/* permissions */
+	do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+	do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+}
+
+int deps_add_tests(CU_pSuite suite)
+{
+	if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
+		return CU_get_error();
+	}
+
+	if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
+		return CU_get_error();
+	}
+
+	return 0;
+}
diff --git a/libsepol/tests/test-deps.h b/libsepol/tests/test-deps.h
new file mode 100644
index 0000000..fbd2ace
--- /dev/null
+++ b/libsepol/tests/test-deps.h
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#ifndef __TEST_DEPS_H__
+#define __TEST_DEPS_H__
+
+#include <CUnit/Basic.h>
+
+int deps_test_init(void);
+int deps_test_cleanup(void);
+int deps_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-downgrade.c b/libsepol/tests/test-downgrade.c
new file mode 100644
index 0000000..1ee7ff4
--- /dev/null
+++ b/libsepol/tests/test-downgrade.c
@@ -0,0 +1,273 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 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 "test-downgrade.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <CUnit/Basic.h>
+
+#define POLICY_BIN_HI	"policies/test-downgrade/policy.hi"
+#define POLICY_BIN_LO	"policies/test-downgrade/policy.lo"
+
+static policydb_t policydb;
+
+/*
+ * Function Name:  downgrade_test_init
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void)
+{
+	/* Initialize the policydb_t structure */
+	if (policydb_init(&policydb)) {
+		fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Function Name:  downgrade_test_cleanup
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void)
+{
+	policydb_destroy(&policydb);
+
+	return 0;
+}
+
+/*
+ * Function Name: downgrade_add_tests
+ *
+ * Input: CU_pSuite
+ *
+ * Output: Returns 0 upon success.  Returns a CUnit error value on failure.
+ *
+ * Description:  Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite)
+{
+	if (CU_add_test(suite, "downgrade", test_downgrade) == NULL)
+		return CU_get_error();
+
+	return 0;
+}
+
+/*
+ * Function Name:  test_downgrade_possible
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description:
+ * Tests the backward compatability of MLS and Non-MLS binary policy versions.
+ */
+void test_downgrade(void)
+{
+	if (do_downgrade_test(0) < 0)
+		fprintf(stderr,
+		        "\nError during downgrade testing of Non-MLS policy\n");
+
+
+	if (do_downgrade_test(1) < 0)
+		fprintf(stderr,
+			"\nError during downgrade testing of MLS policy\n");
+}
+
+/*
+ * Function Name:  do_downgrade_test
+ *
+ * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing
+ *
+ * Output: 0 on success, negative number upon failure
+ *
+ * Description: This function handles the downgrade testing.
+ *              A binary policy is read into the policydb structure, the
+ *              policy version is decreased by a specific amount, written
+ *              back out and then read back in again.  The process is
+ *              repeated until the minimum policy version is reached.
+ */
+int do_downgrade_test(int mls)
+{
+	policydb_t policydb_tmp;
+	int hi, lo, version;
+
+	/* Reset policydb for re-use */
+	policydb_destroy(&policydb);
+	downgrade_test_init();
+
+	/* Read in the hi policy from file */
+	if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) {
+		fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : "");
+		CU_FAIL("Unable to read the binary policy");
+		return -1;
+	}
+
+	/* Change MLS value based on parameter */
+	policydb.mls = mls ? 1 : 0;
+
+	for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) {
+		/* Stash old version number */
+		version = policydb.policyvers;
+
+		/* Try downgrading to each possible version. */
+		for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) {
+
+			/* Reduce policy version */
+			policydb.policyvers = lo;
+
+			/* Write out modified binary policy */
+			if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) {
+				/*
+				 * Error from MLS to pre-MLS is expected due
+				 * to MLS re-implementation in version 19.
+				 */
+				if (mls && lo < POLICYDB_VERSION_MLS)
+					continue;
+
+				fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+				CU_FAIL("Failed to write downgraded binary policy");
+					return -1;
+			}
+
+			/* Make sure we can read back what we wrote. */
+			if (policydb_init(&policydb_tmp)) {
+				fprintf(stderr, "%s:  Out of memory!\n",
+					__FUNCTION__);
+				return -1;
+			}
+			if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) {
+				fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+				CU_FAIL("Unable to read downgraded binary policy");
+				return -1;
+			}
+			policydb_destroy(&policydb_tmp);
+		}
+		/* Restore version number */
+		policydb.policyvers = version;
+    }
+
+    return 0;
+}
+
+/*
+ * Function Name: read_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success.  Upon failure, -1 is returned.
+ *	   Possible failures are, filename with given path does not exist,
+ *	   a failure to open the file, or a failure from prolicydb_read
+ *	   function call.
+ *
+ * Description:  Get a filename, open file and read binary policy into policydb
+ * 				 structure.
+ */
+int read_binary_policy(const char *path, policydb_t *p)
+{
+	FILE *in_fp = NULL;
+	struct policy_file f;
+	int rc;
+
+	/* Open the binary policy file */
+	if ((in_fp = fopen(path, "rb")) == NULL) {
+		fprintf(stderr, "Unable to open %s: %s\n", path,
+			strerror(errno));
+		sepol_handle_destroy(f.handle);
+		return -1;
+	}
+
+	/* Read in the binary policy.  */
+	memset(&f, 0, sizeof(struct policy_file));
+	f.type = PF_USE_STDIO;
+	f.fp = in_fp;
+	rc = policydb_read(p, &f, 0);
+
+	sepol_handle_destroy(f.handle);
+	fclose(in_fp);
+	return rc;
+}
+
+/*
+ * Function Name: write_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success.  Upon failure, -1 is returned.
+ *	   Possible failures are, filename with given path does not exist,
+ *	   a failure to open the file, or a failure from prolicydb_read
+ *	   function call.
+ *
+ * Description:  open file and write the binary policy from policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *p)
+{
+	FILE *out_fp = NULL;
+	struct policy_file f;
+	sepol_handle_t *handle;
+	int rc;
+
+	/* We don't want libsepol to print warnings to stderr */
+	handle = sepol_handle_create();
+	if (handle == NULL) {
+		fprintf(stderr, "Out of memory!\n");
+		return -1;
+	}
+	sepol_msg_set_callback(handle, NULL, NULL);
+
+	/* Open the binary policy file for writing */
+	if ((out_fp = fopen(path, "w" )) == NULL) {
+		fprintf(stderr, "Unable to open %s: %s\n", path,
+			strerror(errno));
+		sepol_handle_destroy(f.handle);
+		return -1;
+	}
+
+	/* Write the binary policy */
+	memset(&f, 0, sizeof(struct policy_file));
+	f.type = PF_USE_STDIO;
+	f.fp = out_fp;
+	f.handle = handle;
+	rc = policydb_write(p, &f);
+
+	sepol_handle_destroy(f.handle);
+	fclose(out_fp);
+	return rc;
+}
diff --git a/libsepol/tests/test-downgrade.h b/libsepol/tests/test-downgrade.h
new file mode 100644
index 0000000..10a7c3b
--- /dev/null
+++ b/libsepol/tests/test-downgrade.h
@@ -0,0 +1,119 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 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
+ */
+
+#ifndef __TEST_DOWNGRADE_H__
+#define __TEST_DOWNGRADE_H__
+
+#include <CUnit/Basic.h>
+#include <sepol/policydb/policydb.h>
+
+/*
+ * Function Name:  downgrade_test_init
+ * 
+ * Input: None
+ * 
+ * Output: None
+ * 
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void);
+
+/*
+ * Function Name:  downgrade_test_cleanup
+ * 
+ * Input: None
+ * 
+ * Output: None
+ * 
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void);
+
+/*
+ * Function Name: downgrade_add_tests
+ * 
+ * Input: CU_pSuite
+ * 
+ * Output: Returns 0 upon success.  Upon failure, a CUnit testing error
+ *	   value is returned
+ * 
+ * Description:  Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite);
+
+/*
+ * Function Name: test_downgrade_possible
+ * 
+ * Input: None
+ * 
+ * Output: None
+ * 
+ * Description: Tests the backward compatability of MLS and Non-MLS binary
+ *		policy versions. 
+ */
+void test_downgrade(void);
+
+/*
+ * Function Name:  do_downgrade_test
+ * 
+ * Input: int that represents a 0 for Non-MLS policy and a 
+ * 		 1 for MLS policy downgrade testing
+ * 
+ * Output: (int) 0 on success, negative number upon failure
+ * 
+ * Description: This function handles the downgrade testing.  A binary policy
+ *		is read into the policydb structure, the policy version is
+ *		decreased by a specific amount, written back out and then read
+ *		back in again. The process is iterative until the minimum
+ *		policy version is reached. 
+ */
+int do_downgrade_test(int mls);
+
+/*
+ * Function Name: read_binary_policy
+ * 
+ * Input: char * which is the path to the file containing the binary policy
+ * 
+ * Output: Returns 0 upon success.  Upon failure, -1 is returned.
+ *	   Possible failures are, filename with given path does not exist,
+ *	   a failure to open the file, or a failure from prolicydb_read
+ *	   function call.
+ * 
+ * Description: Get a filename, open file and read in the binary policy
+ *		into the policydb structure.
+ */
+int read_binary_policy(const char *path, policydb_t *);
+
+/*
+ * Function Name: write_binary_policy
+ * 
+ * Input: char * which is the path to the file containing the binary policy
+ * 
+ * Output: Returns 0 upon success.  Upon failure, -1 is returned.
+ *	   Possible failures are, filename with given path does not exist,
+ *	   a failure to open the file, or a failure from prolicydb_read
+ *	   function call.
+ * 
+ * Description: Get a filename, open file and read in the binary policy
+ *		into the policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *);
+
+#endif
diff --git a/libsepol/tests/test-expander-attr-map.c b/libsepol/tests/test-expander-attr-map.c
new file mode 100644
index 0000000..5c24ced
--- /dev/null
+++ b/libsepol/tests/test-expander-attr-map.c
@@ -0,0 +1,105 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ *          Joshua Brindle <jbrindle@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 "test-expander-attr-map.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t base_expanded2;
+
+void test_expander_attr_mapping(void)
+{
+	/* note that many cases are ommitted because they don't make sense
+	   (i.e. declaring in an optional and then using it in the base) or
+	   because declare in optional then require in a different optional
+	   logic still doesn't work */
+
+	char *typesb1[] = { "attr_check_base_1_1_t", "attr_check_base_1_2_t" };
+	char *typesb2[] = { "attr_check_base_2_1_t", "attr_check_base_2_2_t" };
+	char *typesb3[] = { "attr_check_base_3_1_t", "attr_check_base_3_2_t",
+		"attr_check_base_3_3_t", "attr_check_base_3_4_t"
+	};
+	char *typesb4[] = { "attr_check_base_4_1_t", "attr_check_base_4_2_t" };
+	char *typesb5[] = { "attr_check_base_5_1_t", "attr_check_base_5_2_t" };
+	char *typesb6[] = { "attr_check_base_6_1_t", "attr_check_base_6_2_t",
+		"attr_check_base_6_3_t", "attr_check_base_6_4_t"
+	};
+	char *typesbo2[] = { "attr_check_base_optional_2_1_t",
+		"attr_check_base_optional_2_2_t"
+	};
+	char *typesbo5[] = { "attr_check_base_optional_5_1_t",
+		"attr_check_base_optional_5_2_t"
+	};
+	char *typesm2[] = { "attr_check_mod_2_1_t", "attr_check_mod_2_2_t" };
+	char *typesm4[] = { "attr_check_mod_4_1_t", "attr_check_mod_4_2_t" };
+	char *typesm5[] = { "attr_check_mod_5_1_t", "attr_check_mod_5_2_t" };
+	char *typesm6[] = { "attr_check_mod_6_1_t", "attr_check_mod_6_2_t",
+		"attr_check_mod_6_3_t", "attr_check_mod_6_4_t"
+	};
+	char *typesmo2[] = { "attr_check_mod_optional_4_1_t",
+		"attr_check_mod_optional_4_2_t"
+	};
+	char *typesb10[] = { "attr_check_base_10_1_t", "attr_check_base_10_2_t" };
+	char *typesb11[] = { "attr_check_base_11_3_t", "attr_check_base_11_4_t" };
+	char *typesm10[] = { "attr_check_mod_10_1_t", "attr_check_mod_10_2_t" };
+	char *typesm11[] = { "attr_check_mod_11_3_t", "attr_check_mod_11_4_t" };
+
+	test_attr_types(&base_expanded2, "attr_check_base_1", NULL, typesb1, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_2", NULL, typesb2, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_3", NULL, typesb3, 4);
+	test_attr_types(&base_expanded2, "attr_check_base_4", NULL, typesb4, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_5", NULL, typesb5, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_6", NULL, typesb6, 4);
+	test_attr_types(&base_expanded2, "attr_check_base_optional_2", NULL, typesbo2, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_optional_5", NULL, typesbo5, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_2", NULL, typesm2, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_4", NULL, typesm4, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_5", NULL, typesm5, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_6", NULL, typesm6, 4);
+	test_attr_types(&base_expanded2, "attr_check_mod_optional_4", NULL, typesmo2, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_7", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_base_8", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_base_9", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_base_10", NULL, typesb10, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_11", NULL, typesb11, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_7", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_mod_8", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_mod_9", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_mod_10", NULL, typesm10, 2);
+	test_attr_types(&base_expanded2, "attr_check_mod_11", NULL, typesm11, 2);
+	test_attr_types(&base_expanded2, "attr_check_base_optional_8", NULL, NULL, 0);
+	test_attr_types(&base_expanded2, "attr_check_mod_optional_7", NULL, NULL, 0);
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_1_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_2_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_1_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_2_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_1_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_2_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_1_t"));
+	CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_2_t"));
+}
diff --git a/libsepol/tests/test-expander-attr-map.h b/libsepol/tests/test-expander-attr-map.h
new file mode 100644
index 0000000..6a10089
--- /dev/null
+++ b/libsepol/tests/test-expander-attr-map.h
@@ -0,0 +1,26 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_EXPANDER__ATTR_MAP_H__
+#define __TEST_EXPANDER__ATTR_MAP_H__
+
+void test_expander_attr_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander-roles.c b/libsepol/tests/test-expander-roles.c
new file mode 100644
index 0000000..ecfa88e
--- /dev/null
+++ b/libsepol/tests/test-expander-roles.c
@@ -0,0 +1,37 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ *          Joshua Brindle <jbrindle@tresys.com>
+ *          Chris PeBenito <cpebenito@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 "test-expander-roles.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t role_expanded;
+
+void test_expander_role_mapping(void)
+{
+	char *types1[] = { "role_check_1_1_t", "role_check_1_2_t" };
+
+	test_role_type_set(&role_expanded, "role_check_1", NULL, types1, 2, 0);
+}
diff --git a/libsepol/tests/test-expander-roles.h b/libsepol/tests/test-expander-roles.h
new file mode 100644
index 0000000..380d2ef
--- /dev/null
+++ b/libsepol/tests/test-expander-roles.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@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
+ */
+
+#ifndef __TEST_EXPANDER_ROLE_H__
+#define __TEST_EXPANDER_ROLE_H__
+
+void test_expander_role_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander-users.c b/libsepol/tests/test-expander-users.c
new file mode 100644
index 0000000..549492b
--- /dev/null
+++ b/libsepol/tests/test-expander-users.c
@@ -0,0 +1,75 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ *          Joshua Brindle <jbrindle@tresys.com>
+ *          Chris PeBenito <cpebenito@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 "test-expander-users.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t user_expanded;
+
+static void check_user_roles(policydb_t * p, char *user_name, char **role_names, int num_roles)
+{
+	user_datum_t *user;
+	ebitmap_node_t *tnode;
+	unsigned int i;
+	int j;
+	unsigned char *found;	/* array of booleans of roles found */
+	int extra = 0;		/* number of extra roles found */
+
+	user = (user_datum_t *) hashtab_search(p->p_users.table, user_name);
+	if (!user) {
+		printf("%s not found\n", user_name);
+		CU_FAIL("user not found");
+		return;
+	}
+	found = calloc(num_roles, sizeof(unsigned char));
+	CU_ASSERT_FATAL(found != NULL);
+	ebitmap_for_each_bit(&user->roles.roles, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			extra++;
+			for (j = 0; j < num_roles; j++) {
+				if (strcmp(role_names[j], p->p_role_val_to_name[i]) == 0) {
+					extra--;
+					found[j] += 1;
+					break;
+				}
+			}
+		}
+	}
+	for (j = 0; j < num_roles; j++) {
+		if (found[j] != 1) {
+			printf("role %s associated with user %s %d times\n", role_names[j], user_name, found[j]);
+			CU_FAIL("user mapping failure\n");
+		}
+	}
+	free(found);
+	CU_ASSERT_EQUAL(extra, 0);
+}
+
+void test_expander_user_mapping(void)
+{
+	char *roles1[] = { "user_check_1_1_r", "user_check_1_2_r" };
+
+	check_user_roles(&user_expanded, "user_check_1", roles1, 2);
+}
diff --git a/libsepol/tests/test-expander-users.h b/libsepol/tests/test-expander-users.h
new file mode 100644
index 0000000..cb12143
--- /dev/null
+++ b/libsepol/tests/test-expander-users.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@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
+ */
+
+#ifndef __TEST_EXPANDER_USER_H__
+#define __TEST_EXPANDER_USER_H__
+
+void test_expander_user_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander.c b/libsepol/tests/test-expander.c
new file mode 100644
index 0000000..ded1d9d
--- /dev/null
+++ b/libsepol/tests/test-expander.c
@@ -0,0 +1,218 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ *          Joshua Brindle <jbrindle@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
+ */
+
+/* This is where the expander tests should go, including:
+ * - check role, type, bool, user mapping
+ * - add symbols declared in enabled optionals
+ * - do not add symbols declared in disabled optionals
+ * - add rules from enabled optionals
+ * - do not add rules from disabled optionals
+ * - verify attribute mapping
+
+ * - check conditional expressions for correct mapping
+ */
+
+#include "test-expander.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-expander-users.h"
+#include "test-expander-roles.h"
+#include "test-expander-attr-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <stdlib.h>
+
+policydb_t role_expanded;
+policydb_t user_expanded;
+policydb_t base_expanded2;
+static policydb_t basemod;
+static policydb_t basemod2;
+static policydb_t mod2;
+static policydb_t base_expanded;
+static policydb_t base_only_mod;
+static policydb_t base_only_expanded;
+static policydb_t role_basemod;
+static policydb_t role_mod;
+static policydb_t user_basemod;
+static policydb_t user_mod;
+static policydb_t alias_basemod;
+static policydb_t alias_mod;
+static policydb_t alias_expanded;
+static uint32_t *typemap;
+extern int mls;
+
+/* Takes base, some number of modules, links them, and expands them
+   reads source from myfiles array, which has the base string followed by
+   each module string */
+int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, char **myfiles)
+{
+	char *filename[num_modules + 1];
+	int i;
+
+	for (i = 0; i < num_modules + 1; i++) {
+		filename[i] = calloc(PATH_MAX, sizeof(char));
+		if (snprintf(filename[i], PATH_MAX, "policies/test-expander/%s%s", myfiles[i], mls ? ".mls" : ".std") < 0)
+			return -1;
+	}
+
+	if (policydb_init(mybase)) {
+		fprintf(stderr, "out of memory!\n");
+		return -1;
+	}
+
+	for (i = 0; i < num_modules; i++) {
+		if (policydb_init(mymodules[i])) {
+			fprintf(stderr, "out of memory!\n");
+			return -1;
+		}
+	}
+
+	if (policydb_init(myexpanded)) {
+		fprintf(stderr, "out of memory!\n");
+		return -1;
+	}
+
+	mybase->policy_type = POLICY_BASE;
+	mybase->mls = mls;
+
+	if (read_source_policy(mybase, filename[0], myfiles[0])) {
+		fprintf(stderr, "read source policy failed %s\n", filename[0]);
+		return -1;
+	}
+
+	for (i = 1; i < num_modules + 1; i++) {
+		mymodules[i - 1]->policy_type = POLICY_MOD;
+		mymodules[i - 1]->mls = mls;
+		if (read_source_policy(mymodules[i - 1], filename[i], myfiles[i])) {
+			fprintf(stderr, "read source policy failed %s\n", filename[i]);
+			return -1;
+		}
+	}
+
+	if (link_modules(NULL, mybase, mymodules, num_modules, 0)) {
+		fprintf(stderr, "link modules failed\n");
+		return -1;
+	}
+
+	if (expand_module(NULL, mybase, myexpanded, 0, 0)) {
+		fprintf(stderr, "expand modules failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int expander_test_init(void)
+{
+	char *small_base_file = "small-base.conf";
+	char *base_only_file = "base-base-only.conf";
+	int rc;
+	policydb_t *mymod2;
+	char *files2[] = { "small-base.conf", "module.conf" };
+	char *role_files[] = { "role-base.conf", "role-module.conf" };
+	char *user_files[] = { "user-base.conf", "user-module.conf" };
+	char *alias_files[] = { "alias-base.conf", "alias-module.conf" };
+
+	rc = expander_policy_init(&basemod, 0, NULL, &base_expanded, &small_base_file);
+	if (rc != 0)
+		return rc;
+
+	mymod2 = &mod2;
+	rc = expander_policy_init(&basemod2, 1, &mymod2, &base_expanded2, files2);
+	if (rc != 0)
+		return rc;
+
+	rc = expander_policy_init(&base_only_mod, 0, NULL, &base_only_expanded, &base_only_file);
+	if (rc != 0)
+		return rc;
+
+	mymod2 = &role_mod;
+	rc = expander_policy_init(&role_basemod, 1, &mymod2, &role_expanded, role_files);
+	if (rc != 0)
+		return rc;
+
+	/* Just init the base for now, until we figure out how to separate out
+	   mls and non-mls tests since users can't be used in mls module */
+	mymod2 = &user_mod;
+	rc = expander_policy_init(&user_basemod, 0, NULL, &user_expanded, user_files);
+	if (rc != 0)
+		return rc;
+
+	mymod2 = &alias_mod;
+	rc = expander_policy_init(&alias_basemod, 1, &mymod2, &alias_expanded, alias_files);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+int expander_test_cleanup(void)
+{
+	policydb_destroy(&basemod);
+	policydb_destroy(&base_expanded);
+	free(typemap);
+
+	return 0;
+}
+
+static void test_expander_indexes(void)
+{
+	test_policydb_indexes(&base_expanded);
+}
+
+static void test_expander_alias(void)
+{
+	test_alias_datum(&alias_expanded, "alias_check_1_a", "alias_check_1_t", 1, 0);
+	test_alias_datum(&alias_expanded, "alias_check_2_a", "alias_check_2_t", 1, 0);
+	test_alias_datum(&alias_expanded, "alias_check_3_a", "alias_check_3_t", 1, 0);
+}
+
+int expander_add_tests(CU_pSuite suite)
+{
+	if (NULL == CU_add_test(suite, "expander_indexes", test_expander_indexes)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+
+	if (NULL == CU_add_test(suite, "expander_attr_mapping", test_expander_attr_mapping)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+
+	if (NULL == CU_add_test(suite, "expander_role_mapping", test_expander_role_mapping)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "expander_user_mapping", test_expander_user_mapping)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "expander_alias", test_expander_alias)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	return 0;
+}
diff --git a/libsepol/tests/test-expander.h b/libsepol/tests/test-expander.h
new file mode 100644
index 0000000..5964133
--- /dev/null
+++ b/libsepol/tests/test-expander.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_EXPANDER_H__
+#define __TEST_EXPANDER_H__
+
+#include <CUnit/Basic.h>
+
+int expander_test_init(void);
+int expander_test_cleanup(void);
+int expander_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-linker-cond-map.c b/libsepol/tests/test-linker-cond-map.c
new file mode 100644
index 0000000..0ef0d69
--- /dev/null
+++ b/libsepol/tests/test-linker-cond-map.c
@@ -0,0 +1,159 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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 "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for conditionals
+ * Test each cond/bool for these
+ * - boolean copied correctly (state is correct)
+ * - conditional expression is correct
+ * Tests: 
+ * - single boolean in base
+ * - single boolean in module
+ * - single boolean in base optional
+ * - single boolean in module optional
+ * - 2 booleans in base
+ * - 2 booleans in module
+ * - 2 booleans in base optional
+ * - 2 booleans in module optional
+ * - 2 booleans, base and module
+ * - 2 booleans, base optional and module
+ * - 2 booleans, base optional and module optional
+ * - 3 booleans, base, base optional, module
+ * - 4 boolean, base, base optional, module, module optional
+ */
+
+typedef struct test_cond_expr {
+	char *bool;
+	uint32_t expr_type;
+} test_cond_expr_t;
+
+void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len)
+{
+	int i;
+	cond_expr_t *expr;
+
+	CU_ASSERT_FATAL(d->cond_list != NULL);
+	CU_ASSERT_FATAL(d->cond_list->expr != NULL);
+
+	expr = d->cond_list->expr;
+
+	for (i = 0; i < len; i++) {
+		CU_ASSERT_FATAL(expr != NULL);
+
+		CU_ASSERT(expr->expr_type == bools[i].expr_type);
+		if (bools[i].bool) {
+			CU_ASSERT(strcmp(p->sym_val_to_name[SYM_BOOLS][expr->bool - 1], bools[i].bool) == 0);
+		}
+		expr = expr->next;
+	}
+}
+
+void test_bool_state(policydb_t * p, char *bool, int state)
+{
+	cond_bool_datum_t *b;
+
+	b = hashtab_search(p->p_bools.table, bool);
+	CU_ASSERT_FATAL(b != NULL);
+	CU_ASSERT(b->state == state);
+}
+
+void base_cond_tests(policydb_t * base)
+{
+	avrule_decl_t *d;
+	unsigned int decls[1];
+	test_cond_expr_t bools[2];
+
+	/* these tests look at booleans and conditionals in the base only
+	 * to ensure that they aren't altered or removed during the link process */
+
+	/* bool existance and state, global scope */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "g_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_bool_state(base, "g_b_bool_1", 0);
+	/* conditional expression mapped correctly */
+	bools[0].bool = "g_b_bool_1";
+	bools[0].expr_type = COND_BOOL;
+	test_cond_expr_mapping(base, d, bools, 1);
+
+	/* bool existance and state, optional scope */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "o1_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_bool_state(base, "o1_b_bool_1", 1);
+	/* conditional expression mapped correctly */
+	bools[0].bool = "o1_b_bool_1";
+	bools[0].expr_type = COND_BOOL;
+	test_cond_expr_mapping(base, d, bools, 1);
+
+}
+
+void module_cond_tests(policydb_t * base)
+{
+	avrule_decl_t *d;
+	unsigned int decls[1];
+	test_cond_expr_t bools[3];
+
+	/* bool existance and state, module 1 global scope */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "g_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_bool_state(base, "g_m1_bool_1", 1);
+	/* conditional expression mapped correctly */
+	bools[0].bool = "g_m1_bool_1";
+	bools[0].expr_type = COND_BOOL;
+	test_cond_expr_mapping(base, d, bools, 1);
+
+	/* bool existance and state, module 1 optional scope */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "o1_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_bool_state(base, "o1_m1_bool_1", 0);
+	/* conditional expression mapped correctly */
+	bools[0].bool = "o1_m1_bool_1";
+	bools[0].expr_type = COND_BOOL;
+	test_cond_expr_mapping(base, d, bools, 1);
+
+	/* bool existance and state, module 2 global scope */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "g_m2_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_sym_presence(base, "g_m2_bool_2", SYM_BOOLS, SCOPE_DECL, decls, 1);
+	test_bool_state(base, "g_m2_bool_1", 1);
+	test_bool_state(base, "g_m2_bool_2", 0);
+	/* conditional expression mapped correctly */
+	bools[0].bool = "g_m2_bool_1";
+	bools[0].expr_type = COND_BOOL;
+	bools[1].bool = "g_m2_bool_2";
+	bools[1].expr_type = COND_BOOL;
+	bools[2].bool = NULL;
+	bools[2].expr_type = COND_AND;
+	test_cond_expr_mapping(base, d, bools, 3);
+}
diff --git a/libsepol/tests/test-linker-cond-map.h b/libsepol/tests/test-linker-cond-map.h
new file mode 100644
index 0000000..148c6f6
--- /dev/null
+++ b/libsepol/tests/test-linker-cond-map.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_LINKER_COND_MAP_H__
+#define __TEST_LINKER_COND_MAP_H__
+
+extern void base_cond_tests(policydb_t * base);
+extern void module_cond_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker-roles.c b/libsepol/tests/test-linker-roles.c
new file mode 100644
index 0000000..2c4a804
--- /dev/null
+++ b/libsepol/tests/test-linker-roles.c
@@ -0,0 +1,206 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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 "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for roles:
+ * Test for each of these for 
+ * - role in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type_set
+ * - scope datum has correct decl ids
+ * - dominates bitmap is correct
+ * Tests:
+ * - role in base, no modules
+ * - role in base optional, no modules
+ * - role a in base, b in module
+ * - role a in base and module (additive)
+ * - role a in base and 2 module
+ * - role a in base optional, b in module
+ * - role a in base, b in module optional
+ * - role a in base optional, b in module optional
+ * - role a in base optional and module
+ * - role a in base and module optional
+ * - role a in base optional and module optional
+ * - role a in base optional and 2 modules
+ * - role a and b in base, b dom a, are types correct (TODO)
+ */
+
+/* this simply tests whether the passed in role only has its own 
+ * value in its dominates ebitmap */
+static void only_dominates_self(policydb_t * p, role_datum_t * role)
+{
+	ebitmap_node_t *tnode;
+	unsigned int i;
+	int found = 0;
+
+	ebitmap_for_each_bit(&role->dominates, tnode, i) {
+		if (ebitmap_node_get_bit(tnode, i)) {
+			found++;
+			CU_ASSERT(i == role->s.value - 1);
+		}
+	}
+	CU_ASSERT(found == 1);
+}
+
+void base_role_tests(policydb_t * base)
+{
+	avrule_decl_t *decl;
+	role_datum_t *role;
+	unsigned int decls[2];
+	char *types[2];
+
+	/* These tests look at roles in the base only, the desire is to ensure that
+	 * roles are not destroyed or otherwise removed during the link process */
+
+	/**** test for g_b_role_1 in base and decl 1 (global) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+	/* make sure it has the correct type set (g_b_type_1, no negset, no flags) */
+	types[0] = "g_b_type_1";
+	role = test_role_type_set(base, "g_b_role_1", NULL, types, 1, 0);
+	/* This role should only dominate itself */
+	only_dominates_self(base, role);
+
+	/**** test for o1_b_role_1 in optional (decl 2) ****/
+	decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+	decls[0] = decl->decl_id;
+	test_sym_presence(base, "o1_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+	/* make sure it has the correct type set (o1_b_type_1, no negset, no flags) */
+	types[0] = "o1_b_type_1";
+	role = test_role_type_set(base, "o1_b_role_1", decl, types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+}
+
+void module_role_tests(policydb_t * base)
+{
+	role_datum_t *role;
+	avrule_decl_t *decl;
+	unsigned int decls[3];
+	char *types[3];
+
+	/* These tests are run when the base is linked with 2 modules,
+	 * They should test whether the roles get copied correctly from the 
+	 * modules into the base */
+
+	/**** test for role in module 1 (global) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+	/* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+	types[0] = "g_m1_type_1";
+	role = test_role_type_set(base, "g_m1_role_1", NULL, types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for role in module 1 (optional) ****/
+	decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+	decls[0] = decl->decl_id;
+	test_sym_presence(base, "o1_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+	/* make sure it has the correct type set (o1_m1_type_1, no negset, no flags) */
+	types[0] = "o1_m1_type_1";
+	role = test_role_type_set(base, "o1_m1_role_1", decl, types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/* These test whether the type sets are copied to the right place and
+	 * correctly unioned when they should be */
+
+	/**** test for type added to base role in module 1 (global) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+	/* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+	types[0] = "g_b_type_2";	/* added in base when declared */
+	types[1] = "g_m1_type_1";	/* added in module */
+	role = test_role_type_set(base, "g_b_role_2", NULL, types, 2, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for type added to base role in module 1 & 2 (global) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+	test_sym_presence(base, "g_b_role_3", SYM_ROLES, SCOPE_DECL, decls, 3);
+	/* make sure it has the correct type set (g_b_type_2, g_m1_type_2, g_m2_type_2, no negset, no flags) */
+	types[0] = "g_b_type_2";	/* added in base when declared */
+	types[1] = "g_m1_type_2";	/* added in module 1 */
+	types[2] = "g_m2_type_2";	/* added in module 2 */
+	role = test_role_type_set(base, "g_b_role_3", NULL, types, 3, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for role in base optional and module 1 (additive) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "o1_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+	/* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+	types[0] = "g_m1_type_1";
+	role = test_role_type_set(base, "o1_b_role_2", NULL, types, 1, 0);
+	types[0] = "o1_b_type_1";
+	role = test_role_type_set(base, "o1_b_role_2", test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"), types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for role in base and module 1 optional (additive) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"))->decl_id;
+	test_sym_presence(base, "g_b_role_4", SYM_ROLES, SCOPE_DECL, decls, 2);
+	/* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+	types[0] = "g_b_type_2";
+	role = test_role_type_set(base, "g_b_role_4", NULL, types, 1, 0);
+	types[0] = "g_m1_type_2";
+	role = test_role_type_set(base, "g_b_role_4", test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"), types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for role in base and module 1 optional (additive) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+	test_sym_presence(base, "o3_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 2);
+	/* this one will have 2 type sets, one in the 3rd base optional and one in the 3rd module optional */
+	types[0] = "o3_b_type_1";
+	role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"), types, 1, 0);
+	types[0] = "o3_m1_type_1";
+	role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"), types, 1, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+
+	/**** test for role in base and module 1 optional (additive) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+	decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+	test_sym_presence(base, "o4_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 3);
+	/* this one will have 2 type sets, one in the global symtab (with both module types) and one in the 4th optional of base */
+	types[0] = "g_m1_type_1";
+	role = test_role_type_set(base, "o4_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"), types, 1, 0);
+	types[0] = "g_m2_type_1";
+	types[1] = "g_m1_type_2";
+	role = test_role_type_set(base, "o4_b_role_1", NULL, types, 2, 0);
+	/* and only dominates itself */
+	only_dominates_self(base, role);
+}
diff --git a/libsepol/tests/test-linker-roles.h b/libsepol/tests/test-linker-roles.h
new file mode 100644
index 0000000..f7407df
--- /dev/null
+++ b/libsepol/tests/test-linker-roles.h
@@ -0,0 +1,29 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_LINKER_ROLES_H__
+#define __TEST_LINKER_ROLES_H__
+
+#include <sepol/policydb/policydb.h>
+
+extern void base_role_tests(policydb_t * base);
+extern void module_role_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker-types.c b/libsepol/tests/test-linker-types.c
new file mode 100644
index 0000000..94f16ac
--- /dev/null
+++ b/libsepol/tests/test-linker-types.c
@@ -0,0 +1,317 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *         Chad Sellers <csellers@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 "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for types:
+ * Test for each of these for 
+ * - type in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type bitmap (if attr)
+ * - primary is set correctly
+ * - scope datum has correct decl ids
+ * Tests:
+ * - type in base, no modules
+ * - type in base optional, no modules
+ * - type a in base, b in module
+ * - type a in base optional, b in module
+ * - type a in base, b in module optional
+ * - type a in base optional, b in module optional
+ * - attr in base, no modules
+ * - attr in base optional, no modules
+ * - attr a in base, b in module
+ * - attr a in base optional, b in module
+ * - attr a in base, b in module optional
+ * - attr a in base optional, b in module optional
+ * - attr a declared in base, added to in module
+ * - attr a declared in base, added to in module optional
+ * - attr a declared in base, added to in 2 modules 
+ * - attr a declared in base, added to in 2 modules (optional and global)
+ * - attr a declared in base optional, added to in module
+ * - attr a declared in base optional, added to in module optional
+ * - attr a added to in base optional, declared in module
+ * - attr a added to in base optional, declared in module optional
+ * - attr a added to in base optional, declared in module, added to in other module
+ * - attr a added to in base optional, declared in module optional, added to in other module
+ * - attr a added to in base optional, declared in module , added to in other module optional
+ * - attr a added to in base optional, declared in module optional, added to in other module optional
+ * - alias in base of primary type in base, no modules
+ * - alias in base optional of primary type in base, no modules
+ * - alias in base optional of primary type in base optional
+ * - alias in module of primary type in base
+ * - alias in module optional of primary type in base
+ * - alias in module optional of primary type in base optional
+ * - alias in module of primary type in module
+ * - alias in module optional of primary type in module
+ * - alias in module optional of primary type in module optional
+ * - alias a in base, b in module, primary type in base
+ * - alias a in base, b in module, primary type in module
+ * - alias a in base optional, b in module, primary type in base
+ * - alias a in base optional, b in module, primary type in module
+ * - alias a in base, b in module optional, primary type in base
+ * - alias a in base, b in module optional, primary type in module
+ * - alias a in base optional, b in module optional, primary type in base
+ * - alias a in base optional, b in module optional, primary type in module
+ * - alias a in base, required in module, primary type in base
+ * - alias a in base, required in base optional, primary type in base
+ * - alias a in base, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in base
+ * - alias a in module, required in module optional, primary type in base
+ * - alias a in base optional, required in module, primary type in base
+ * - alias a in base optional, required in different base optional, primary type in base
+ * - alias a in base optional, required in module optional, primary type in base
+ * - alias a in module optional, required in base optional, primary type in base
+ * - alias a in module optional, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in module
+ * - alias a in module, required in module optional, primary type in module
+ * - alias a in base optional, required in module, primary type in module
+ * - alias a in base optional, required in different base optional, primary type in module
+ * - alias a in base optional, required in module optional, primary type in module
+ * - alias a in module optional, required in base optional, primary type in module
+ * - alias a in module optional, required in module optional, primary type in module
+ */
+
+/* Don't pass in decls from global blocks since symbols aren't stored in their symtab */
+static void test_type_datum(policydb_t * p, char *id, unsigned int *decls, int len, unsigned int primary)
+{
+	int i;
+	unsigned int value;
+	type_datum_t *type;
+
+	/* just test the type datums for each decl to see if it is what we expect */
+	type = hashtab_search(p->p_types.table, id);
+
+	CU_ASSERT_FATAL(type != NULL);
+	CU_ASSERT(type->primary == primary);
+	CU_ASSERT(type->flavor == TYPE_TYPE);
+
+	value = type->s.value;
+
+	for (i = 0; i < len; i++) {
+		type = hashtab_search(p->decl_val_to_struct[decls[i] - 1]->p_types.table, id);
+		CU_ASSERT_FATAL(type != NULL);
+		CU_ASSERT(type->primary == primary);
+		CU_ASSERT(type->flavor == TYPE_TYPE);
+		CU_ASSERT(type->s.value == value);
+	}
+
+}
+
+void base_type_tests(policydb_t * base)
+{
+	unsigned int decls[2];
+	char *types[2];
+
+	/* These tests look at types in the base only, the desire is to ensure that
+	 * types are not destroyed or otherwise removed during the link process.
+	 * if this happens these tests won't work anyway since we are using types to 
+	 * mark blocks */
+
+	/**** test for g_b_type_1 in base and decl 1 (global) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_type_datum(base, "g_b_type_1", NULL, 0, 1);
+	/* this attr is in the same decl as the type */
+	test_sym_presence(base, "g_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_b_type_1";
+	test_attr_types(base, "g_b_attr_1", NULL, types, 1);
+
+	/**** test for o1_b_type_1 in optional (decl 2) ****/
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+	test_sym_presence(base, "o1_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_type_datum(base, "o1_b_type_1", NULL, 0, 1);
+	/* this attr is in the same decl as the type */
+	test_sym_presence(base, "o1_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "o1_b_type_1";
+	test_attr_types(base, "o1_b_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+	/* tests for aliases */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_alias_datum(base, "g_b_alias_1", "g_b_type_3", 1, 0);
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o6_b"))->decl_id;
+	test_sym_presence(base, "g_b_alias_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_alias_datum(base, "g_b_alias_2", "g_b_type_3", 1, 0);
+
+}
+
+void module_type_tests(policydb_t * base)
+{
+	unsigned int decls[2];
+	char *types[2];
+	avrule_decl_t *d;
+
+	/* These tests look at types that were copied from modules or attributes
+	 * that were modified and declared in modules and base. These apply to 
+	 * declarations and modifications in and out of optionals. These tests
+	 * should ensure that types and attributes are correctly copied from modules
+	 * and that attribute type sets are correctly copied and mapped. */
+
+	/* note: scope for attributes is currently smashed if the attribute is declared 
+	 * somewhere so the scope test only looks at global, the type bitmap test looks
+	 * at the appropriate decl symtab */
+
+	/* test for type in module 1 (global) */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_type_datum(base, "g_m1_type_1", NULL, 0, 1);
+	/* attr has is in the same decl as the above type */
+	test_sym_presence(base, "g_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_1";
+	types[1] = "g_m1_type_2";
+	test_attr_types(base, "g_m1_attr_1", NULL, types, 2);
+
+	/* test for type in module 1 (optional) */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+	test_sym_presence(base, "o1_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_type_datum(base, "o1_m1_type_1", NULL, 0, 1);
+	/* attr has is in the same decl as the above type */
+	test_sym_presence(base, "o1_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "o1_m1_type_2";
+	test_attr_types(base, "o1_m1_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+	/* test for attr declared in base, added to in module (global). 
+	 * Since these are both global it'll be merged in the main symtab */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_3";
+	test_attr_types(base, "g_b_attr_3", NULL, types, 1);
+
+	/* test for attr declared in base, added to in module (optional). */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+	types[0] = "o1_m1_type_3";
+	test_attr_types(base, "g_b_attr_4", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+	/* test for attr declared in base, added to in 2 modules (global). (merged in main symtab) */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_attr_5", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_4";
+	types[1] = "g_m2_type_4";
+	test_attr_types(base, "g_b_attr_5", NULL, types, 2);
+
+	/* test for attr declared in base, added to in 2 modules (optional/global). */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+	test_sym_presence(base, "g_b_attr_6", SYM_TYPES, SCOPE_DECL, decls, 1);
+	/* module 2 was global to its type is in main symtab */
+	types[0] = "g_m2_type_5";
+	test_attr_types(base, "g_b_attr_6", NULL, types, 1);
+	d = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"));
+	types[0] = "o3_m1_type_2";
+	test_attr_types(base, "g_b_attr_6", d, types, 1);
+
+	/* test for attr declared in base optional, added to in module (global). */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+	test_sym_presence(base, "o4_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_5";
+	test_attr_types(base, "o4_b_attr_1", NULL, types, 1);
+
+	/* test for attr declared in base optional, added to in module (optional). */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+	test_sym_presence(base, "o1_b_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+	types[0] = "o1_m1_type_5";
+	test_attr_types(base, "o1_b_attr_2", d, types, 1);
+
+	/* test for attr declared in module, added to in base optional */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+	types[0] = "o1_b_type_2";
+	test_attr_types(base, "g_m1_attr_2", d, types, 1);
+
+	/* test for attr declared in module optional, added to in base optional */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+	test_sym_presence(base, "o3_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+	types[0] = "o4_b_type_1";
+	test_attr_types(base, "o3_m1_attr_1", d, types, 1);
+
+	/* attr a added to in base optional, declared/added to in module, added to in other module */
+	/* first the module declare/add and module 2 add (since its global it'll be in the main symtab */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m1_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_6";
+	types[1] = "g_m2_type_3";
+	test_attr_types(base, "g_m1_attr_3", NULL, types, 2);
+	/* base add */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+	types[0] = "o4_b_type_2";
+	test_attr_types(base, "g_m1_attr_3", d, types, 1);
+
+	/* attr a added to in base optional, declared/added in module optional, added to in other module */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "o3_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "o3_m1_type_3";
+	test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+	/* module 2's type will be in the main symtab */
+	types[0] = "g_m2_type_6";
+	test_attr_types(base, "o3_m1_attr_2", NULL, types, 1);
+	/* base add */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_b");
+	types[0] = "o2_b_type_1";
+	test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+
+	/* attr a added to in base optional, declared/added in module , added to in other module optional */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m1_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "g_m1_type_7";
+	test_attr_types(base, "g_m1_attr_4", NULL, types, 1);
+	/* module 2 */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+	types[0] = "o2_m2_type_1";
+	test_attr_types(base, "g_m1_attr_4", d, types, 1);
+	/* base add */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+	types[0] = "o5_b_type_1";
+	test_attr_types(base, "g_m1_attr_4", d, types, 1);
+
+	/* attr a added to in base optional, declared/added in module optional, added to in other module optional */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_m1");
+	decls[0] = d->decl_id;
+	test_sym_presence(base, "o4_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	types[0] = "o4_m1_type_1";
+	test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+	/* module 2 */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+	types[0] = "o2_m2_type_2";
+	test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+	/* base add */
+	d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+	types[0] = "o5_b_type_2";
+	test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+
+	/* tests for aliases */
+	decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+	test_sym_presence(base, "g_m_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+	test_alias_datum(base, "g_m_alias_1", "g_b_type_3", 1, 0);
+
+}
diff --git a/libsepol/tests/test-linker-types.h b/libsepol/tests/test-linker-types.h
new file mode 100644
index 0000000..0c860eb
--- /dev/null
+++ b/libsepol/tests/test-linker-types.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_LINKER_TYPES_H__
+#define __TEST_LINKER_TYPES_H__
+
+extern void base_type_tests(policydb_t * base);
+extern void module_type_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker.c b/libsepol/tests/test-linker.c
new file mode 100644
index 0000000..d08f219
--- /dev/null
+++ b/libsepol/tests/test-linker.c
@@ -0,0 +1,154 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+/* This is where the linker tests should go, including:
+ * - check role, type, bool, user, attr mapping
+ * - check for properly enabled optional
+ * - check for properly disabled optional
+ * - check for non-optional disabled blocks
+ * - properly add symbols declared in optionals
+ */
+
+#include "test-linker.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-linker-roles.h"
+#include "test-linker-types.h"
+#include "test-linker-cond-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define NUM_MODS 2
+#define NUM_POLICIES NUM_MODS+1
+
+#define BASEMOD NUM_MODS
+const char *policies[NUM_POLICIES] = {
+	"module1.conf",
+	"module2.conf",
+	"small-base.conf",
+};
+
+static policydb_t basenomods;
+static policydb_t linkedbase;
+static policydb_t *modules[NUM_MODS];
+extern int mls;
+
+int linker_test_init(void)
+{
+	int i;
+
+	if (test_load_policy(&linkedbase, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+		return -1;
+
+	if (test_load_policy(&basenomods, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+		return -1;
+
+	for (i = 0; i < NUM_MODS; i++) {
+
+		modules[i] = calloc(1, sizeof(*modules[i]));
+		if (!modules[i]) {
+			fprintf(stderr, "out of memory!\n");
+			return -1;
+		}
+
+		if (test_load_policy(modules[i], POLICY_MOD, mls, "test-linker", policies[i]))
+			return -1;
+
+	}
+
+	if (link_modules(NULL, &linkedbase, modules, NUM_MODS, 0)) {
+		fprintf(stderr, "link modules failed\n");
+		return -1;
+	}
+
+	if (link_modules(NULL, &basenomods, NULL, 0, 0)) {
+		fprintf(stderr, "link modules failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int linker_test_cleanup(void)
+{
+	int i;
+
+	policydb_destroy(&basenomods);
+	policydb_destroy(&linkedbase);
+
+	for (i = 0; i < NUM_MODS; i++) {
+		policydb_destroy(modules[i]);
+		free(modules[i]);
+	}
+	return 0;
+}
+
+static void test_linker_indexes(void)
+{
+	test_policydb_indexes(&linkedbase);
+}
+
+static void test_linker_roles(void)
+{
+	base_role_tests(&basenomods);
+	base_role_tests(&linkedbase);
+	module_role_tests(&linkedbase);
+}
+
+static void test_linker_types(void)
+{
+	base_type_tests(&basenomods);
+	base_type_tests(&linkedbase);
+	module_type_tests(&linkedbase);
+}
+
+static void test_linker_cond(void)
+{
+	base_cond_tests(&basenomods);
+	base_cond_tests(&linkedbase);
+	module_cond_tests(&linkedbase);
+}
+
+int linker_add_tests(CU_pSuite suite)
+{
+	if (NULL == CU_add_test(suite, "linker_indexes", test_linker_indexes)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "linker_types", test_linker_types)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "linker_roles", test_linker_roles)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	if (NULL == CU_add_test(suite, "linker_cond", test_linker_cond)) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	return 0;
+}
diff --git a/libsepol/tests/test-linker.h b/libsepol/tests/test-linker.h
new file mode 100644
index 0000000..16339a0
--- /dev/null
+++ b/libsepol/tests/test-linker.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@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
+ */
+
+#ifndef __TEST_LINKER_H__
+#define __TEST_LINKER_H__
+
+#include <CUnit/Basic.h>
+
+int linker_test_init(void);
+int linker_test_cleanup(void);
+int linker_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/utils/Makefile b/libsepol/utils/Makefile
new file mode 100644
index 0000000..6864114
--- /dev/null
+++ b/libsepol/utils/Makefile
@@ -0,0 +1,24 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+BINDIR ?= $(PREFIX)/bin
+
+CFLAGS ?= -Wall -Werror
+override CFLAGS += -I../include
+LDLIBS += -L../src -lsepol 
+
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+
+all: $(TARGETS)
+
+install: all
+	-mkdir -p $(BINDIR)
+	install -m 755 $(TARGETS) $(BINDIR)
+
+clean:
+	-rm -f $(TARGETS) *.o 
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
+relabel:
+
diff --git a/libsepol/utils/chkcon.c b/libsepol/utils/chkcon.c
new file mode 100644
index 0000000..baa5117
--- /dev/null
+++ b/libsepol/utils/chkcon.c
@@ -0,0 +1,44 @@
+#include <sepol/sepol.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+void usage(char*) __attribute__((noreturn));
+
+void usage(char *progname)
+{
+	printf("usage:  %s policy context\n", progname);
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	FILE *fp;
+
+	if (argc != 3)
+		usage(argv[0]);
+
+	fp = fopen(argv[1], "r");
+	if (!fp) {
+		fprintf(stderr, "Can't open '%s':  %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	if (sepol_set_policydb_from_file(fp) < 0) {
+		fprintf(stderr, "Error while processing %s:  %s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	fclose(fp);
+
+	if (sepol_check_context(argv[2]) < 0) {
+		fprintf(stderr, "%s is not valid\n", argv[2]);
+		exit(1);
+	}
+
+	printf("%s is valid\n", argv[2]);
+	exit(0);
+}