Import libsepol 2.1.0 (Release 2011-07-27).
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a74c98b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+utils/chkcon
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..8d9c9c0
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,750 @@
+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/Makefile b/Makefile
new file mode 100644
index 0000000..d526965
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+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/VERSION b/VERSION
new file mode 100644
index 0000000..7ec1d6d
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+2.1.0
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 0000000..0cd00ab
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,12 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCDIR ?= $(PREFIX)/include/sepol
+
+install:
+	test -d $(INCDIR) || install -m 755 -d $(INCDIR)
+	test -d $(INCDIR)/policydb || install -m 755 -d $(INCDIR)/policydb
+	install -m 644 $(wildcard sepol/*.h) $(INCDIR)
+	install -m 644 $(wildcard sepol/policydb/*.h) $(INCDIR)/policydb
+
+indent:
+	../../scripts/Lindent $(wildcard sepol/*.h)
diff --git a/include/sepol/boolean_record.h b/include/sepol/boolean_record.h
new file mode 100644
index 0000000..54ca021
--- /dev/null
+++ b/include/sepol/boolean_record.h
@@ -0,0 +1,51 @@
+#ifndef _SEPOL_BOOLEAN_RECORD_H_
+#define _SEPOL_BOOLEAN_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+
+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);
+
+#endif
diff --git a/include/sepol/booleans.h b/include/sepol/booleans.h
new file mode 100644
index 0000000..95ee7de
--- /dev/null
+++ b/include/sepol/booleans.h
@@ -0,0 +1,59 @@
+#ifndef _SEPOL_BOOLEANS_H_
+#define _SEPOL_BOOLEANS_H_
+
+#include <stddef.h>
+#include <sepol/policydb.h>
+#include <sepol/boolean_record.h>
+#include <sepol/handle.h>
+
+/*--------------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);
+
+#endif
diff --git a/include/sepol/context.h b/include/sepol/context.h
new file mode 100644
index 0000000..c1eadca
--- /dev/null
+++ b/include/sepol/context.h
@@ -0,0 +1,25 @@
+#ifndef _SEPOL_CONTEXT_H_
+#define _SEPOL_CONTEXT_H_
+
+#include <sepol/context_record.h>
+#include <sepol/policydb.h>
+#include <sepol/handle.h>
+
+/* -- 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);
+#endif
diff --git a/include/sepol/context_record.h b/include/sepol/context_record.h
new file mode 100644
index 0000000..c305480
--- /dev/null
+++ b/include/sepol/context_record.h
@@ -0,0 +1,53 @@
+#ifndef _SEPOL_CONTEXT_RECORD_H_
+#define _SEPOL_CONTEXT_RECORD_H_
+
+#include <sepol/handle.h>
+
+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);
+
+#endif
diff --git a/include/sepol/debug.h b/include/sepol/debug.h
new file mode 100644
index 0000000..3370845
--- /dev/null
+++ b/include/sepol/debug.h
@@ -0,0 +1,34 @@
+#ifndef _SEPOL_DEBUG_H_
+#define _SEPOL_DEBUG_H_
+
+#include <sepol/handle.h>
+
+/* 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);
+#endif
diff --git a/include/sepol/errcodes.h b/include/sepol/errcodes.h
new file mode 100644
index 0000000..c6f3a8b
--- /dev/null
+++ b/include/sepol/errcodes.h
@@ -0,0 +1,25 @@
+/* Author: Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_errno_h__
+#define __sepol_errno_h__
+
+#include <errno.h>
+
+#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
+
+#endif
diff --git a/include/sepol/handle.h b/include/sepol/handle.h
new file mode 100644
index 0000000..19be326
--- /dev/null
+++ b/include/sepol/handle.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_HANDLE_H_
+#define _SEPOL_HANDLE_H_
+
+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 *);
+
+#endif
diff --git a/include/sepol/iface_record.h b/include/sepol/iface_record.h
new file mode 100644
index 0000000..a72678c
--- /dev/null
+++ b/include/sepol/iface_record.h
@@ -0,0 +1,59 @@
+#ifndef _SEPOL_IFACE_RECORD_H_
+#define _SEPOL_IFACE_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sepol/context_record.h>
+
+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);
+
+#endif
diff --git a/include/sepol/interfaces.h b/include/sepol/interfaces.h
new file mode 100644
index 0000000..9849e13
--- /dev/null
+++ b/include/sepol/interfaces.h
@@ -0,0 +1,43 @@
+#ifndef __SEPOL_INTERFACES_H_
+#define __SEPOL_INTERFACES_H_
+
+#include <sepol/policydb.h>
+#include <sepol/iface_record.h>
+#include <sepol/handle.h>
+
+/* 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);
+
+#endif
diff --git a/include/sepol/module.h b/include/sepol/module.h
new file mode 100644
index 0000000..35f5cb7
--- /dev/null
+++ b/include/sepol/module.h
@@ -0,0 +1,82 @@
+#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>
+
+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);
+
+#endif
diff --git a/include/sepol/node_record.h b/include/sepol/node_record.h
new file mode 100644
index 0000000..9f61ac7
--- /dev/null
+++ b/include/sepol/node_record.h
@@ -0,0 +1,92 @@
+#ifndef _SEPOL_NODE_RECORD_H_
+#define _SEPOL_NODE_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+
+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);
+
+#endif
diff --git a/include/sepol/nodes.h b/include/sepol/nodes.h
new file mode 100644
index 0000000..1e0ac4f
--- /dev/null
+++ b/include/sepol/nodes.h
@@ -0,0 +1,40 @@
+#ifndef _SEPOL_NODES_H_
+#define _SEPOL_NODES_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/node_record.h>
+
+/* 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);
+
+#endif
diff --git a/include/sepol/policydb.h b/include/sepol/policydb.h
new file mode 100644
index 0000000..43e23b3
--- /dev/null
+++ b/include/sepol/policydb.h
@@ -0,0 +1,138 @@
+#ifndef _SEPOL_POLICYDB_H_
+#define _SEPOL_POLICYDB_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <sepol/handle.h>
+
+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);
+
+/* 
+ * 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);
+
+#endif
diff --git a/include/sepol/policydb/avrule_block.h b/include/sepol/policydb/avrule_block.h
new file mode 100644
index 0000000..dc926e5
--- /dev/null
+++ b/include/sepol/policydb/avrule_block.h
@@ -0,0 +1,37 @@
+/* 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>
+
+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);
+
+#endif
diff --git a/include/sepol/policydb/avtab.h b/include/sepol/policydb/avtab.h
new file mode 100644
index 0000000..6955ecf
--- /dev/null
+++ b/include/sepol/policydb/avtab.h
@@ -0,0 +1,127 @@
+
+/* 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/types.h>
+#include <stdint.h>
+
+typedef struct avtab_key {
+	uint16_t source_type;
+	uint16_t target_type;
+	uint16_t target_class;
+#define AVTAB_ALLOWED     1
+#define AVTAB_AUDITALLOW  2
+#define AVTAB_AUDITDENY   4
+#define AVTAB_NEVERALLOW 128
+#define AVTAB_AV         (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 16
+#define AVTAB_MEMBER     32
+#define AVTAB_CHANGE     64
+#define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#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_datum {
+	uint32_t data;		/* access vector or type */
+} 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 */
+	uint16_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 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
+
+#endif				/* _AVTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/conditional.h b/include/sepol/policydb/conditional.h
new file mode 100644
index 0000000..a8ed694
--- /dev/null
+++ b/include/sepol/policydb/conditional.h
@@ -0,0 +1,134 @@
+/* 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>
+
+#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 using 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;
+} 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);
+
+#endif				/* _CONDITIONAL_H_ */
diff --git a/include/sepol/policydb/constraint.h b/include/sepol/policydb/constraint.h
new file mode 100644
index 0000000..4c16ab0
--- /dev/null
+++ b/include/sepol/policydb/constraint.h
@@ -0,0 +1,77 @@
+
+/* 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>
+
+#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);
+
+#endif				/* _CONSTRAINT_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/context.h b/include/sepol/policydb/context.h
new file mode 100644
index 0000000..8d74a25
--- /dev/null
+++ b/include/sepol/policydb/context.h
@@ -0,0 +1,97 @@
+
+/* 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>
+
+/*
+ * 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));
+}
+
+#endif
diff --git a/include/sepol/policydb/ebitmap.h b/include/sepol/policydb/ebitmap.h
new file mode 100644
index 0000000..410c15c
--- /dev/null
+++ b/include/sepol/policydb/ebitmap.h
@@ -0,0 +1,88 @@
+
+/* 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>
+
+#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_cpy(ebitmap_t * dst, const ebitmap_t * src);
+extern int ebitmap_contains(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);
+
+#endif				/* _EBITMAP_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/expand.h b/include/sepol/policydb/expand.h
new file mode 100644
index 0000000..31e25ec
--- /dev/null
+++ b/include/sepol/policydb/expand.h
@@ -0,0 +1,79 @@
+/* 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>
+
+/*
+ * 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);
+
+#endif
diff --git a/include/sepol/policydb/flask.h b/include/sepol/policydb/flask.h
new file mode 100644
index 0000000..3134284
--- /dev/null
+++ b/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/include/sepol/policydb/flask_types.h b/include/sepol/policydb/flask_types.h
new file mode 100644
index 0000000..575c6f2
--- /dev/null
+++ b/include/sepol/policydb/flask_types.h
@@ -0,0 +1,62 @@
+
+/* -*- 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>
+
+/*
+ * 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;
+};
+
+#endif
diff --git a/include/sepol/policydb/hashtab.h b/include/sepol/policydb/hashtab.h
new file mode 100644
index 0000000..1081ff6
--- /dev/null
+++ b/include/sepol/policydb/hashtab.h
@@ -0,0 +1,137 @@
+
+/* 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>
+
+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);
+
+#endif
diff --git a/include/sepol/policydb/hierarchy.h b/include/sepol/policydb/hierarchy.h
new file mode 100644
index 0000000..de2dfc7
--- /dev/null
+++ b/include/sepol/policydb/hierarchy.h
@@ -0,0 +1,32 @@
+/* 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/policydb.h>
+
+extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p);
+
+#endif
diff --git a/include/sepol/policydb/link.h b/include/sepol/policydb/link.h
new file mode 100644
index 0000000..fca9114
--- /dev/null
+++ b/include/sepol/policydb/link.h
@@ -0,0 +1,20 @@
+/* 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>
+
+extern int link_modules(sepol_handle_t * handle,
+			policydb_t * b, policydb_t ** mods, int len,
+			int verbose);
+
+#endif
diff --git a/include/sepol/policydb/mls_types.h b/include/sepol/policydb/mls_types.h
new file mode 100644
index 0000000..e491209
--- /dev/null
+++ b/include/sepol/policydb/mls_types.h
@@ -0,0 +1,153 @@
+
+/* 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>
+
+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);
+
+#endif
diff --git a/include/sepol/policydb/module.h b/include/sepol/policydb/module.h
new file mode 100644
index 0000000..10403c8
--- /dev/null
+++ b/include/sepol/policydb/module.h
@@ -0,0 +1,48 @@
+/* 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>
+
+#define SEPOL_MODULE_PACKAGE_MAGIC 0xf97cff8f
+
+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);
+
+#endif
diff --git a/include/sepol/policydb/polcaps.h b/include/sepol/policydb/polcaps.h
new file mode 100644
index 0000000..40c0a48
--- /dev/null
+++ b/include/sepol/policydb/polcaps.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_POLICYDB_POLCAPS_H_
+#define _SEPOL_POLICYDB_POLCAPS_H_
+
+/* Policy capabilities */
+enum {
+	POLICYDB_CAPABILITY_NETPEER,
+	POLICYDB_CAPABILITY_OPENPERM,
+	__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);
+
+#endif /* _SEPOL_POLICYDB_POLCAPS_H_ */
diff --git a/include/sepol/policydb/policydb.h b/include/sepol/policydb/policydb.h
new file mode 100644
index 0000000..5320bc8
--- /dev/null
+++ b/include/sepol/policydb/policydb.h
@@ -0,0 +1,724 @@
+
+/* 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>
+
+#define ERRMSG_LEN 1024
+
+#define POLICYDB_SUCCESS      0
+#define POLICYDB_ERROR       -1
+#define POLICYDB_UNSUPPORTED -2
+
+/*
+ * 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 */
+} 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;
+} 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 class;
+	uint32_t data;		/* permissions or new type */
+	struct class_perm_node *next;
+} class_perm_node_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     1
+#define AVRULE_AUDITALLOW  2
+#define AVRULE_AUDITDENY   4
+#define AVRULE_DONTAUDIT   8
+#define AVRULE_NEVERALLOW 128
+#define AVRULE_AV         (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define AVRULE_TRANSITION 16
+#define AVRULE_MEMBER     32
+#define AVRULE_CHANGE     64
+#define AVRULE_TYPE       (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+	uint32_t specified;
+#define RULE_SELF 1
+	uint32_t flags;
+	type_set_t stypes;
+	type_set_t ttypes;
+	class_perm_node_t *perms;
+	unsigned long line;	/* line number from policy.conf where
+				 * this rule originated  */
+	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 {
+			uint32_t low_iomem;
+			uint32_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 */
+
+/* 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_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
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_ROLETRANS
+
+/* 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_MIN MOD_POLICYDB_VERSION_BASE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_ROLEATTRIB
+
+#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"
+#define SEPOL_TARGET_SELINUX 0
+#define SEPOL_TARGET_XEN     1
+
+
+#endif				/* _POLICYDB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/services.h b/include/sepol/policydb/services.h
new file mode 100644
index 0000000..aef0c7b
--- /dev/null
+++ b/include/sepol/policydb/services.h
@@ -0,0 +1,184 @@
+
+/* -*- 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>
+
+/* 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);
+
+/*
+ * 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 */
+			   char *name,	/* IN */
+			   sepol_security_class_t sclass,	/* IN */
+			   sepol_security_id_t * sid);	/* OUT  */
+
+#endif
diff --git a/include/sepol/policydb/sidtab.h b/include/sepol/policydb/sidtab.h
new file mode 100644
index 0000000..33c7cb5
--- /dev/null
+++ b/include/sepol/policydb/sidtab.h
@@ -0,0 +1,72 @@
+
+/* 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>
+
+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);
+
+#endif				/* _SIDTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/symtab.h b/include/sepol/policydb/symtab.h
new file mode 100644
index 0000000..c8ad664
--- /dev/null
+++ b/include/sepol/policydb/symtab.h
@@ -0,0 +1,38 @@
+
+/* 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>
+
+/* 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);
+
+#endif				/* _SYMTAB_H_ */
+
+/* FLASK */
diff --git a/include/sepol/policydb/util.h b/include/sepol/policydb/util.h
new file mode 100644
index 0000000..40bfaa6
--- /dev/null
+++ b/include/sepol/policydb/util.h
@@ -0,0 +1,31 @@
+/* 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__
+
+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);
+
+#endif
diff --git a/include/sepol/port_record.h b/include/sepol/port_record.h
new file mode 100644
index 0000000..b347e08
--- /dev/null
+++ b/include/sepol/port_record.h
@@ -0,0 +1,66 @@
+#ifndef _SEPOL_PORT_RECORD_H_
+#define _SEPOL_PORT_RECORD_H_
+
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+
+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
+
+/* 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);
+
+#endif
diff --git a/include/sepol/ports.h b/include/sepol/ports.h
new file mode 100644
index 0000000..fb94117
--- /dev/null
+++ b/include/sepol/ports.h
@@ -0,0 +1,40 @@
+#ifndef _SEPOL_PORTS_H_
+#define _SEPOL_PORTS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/port_record.h>
+
+/* 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);
+
+#endif
diff --git a/include/sepol/roles.h b/include/sepol/roles.h
new file mode 100644
index 0000000..113f9d2
--- /dev/null
+++ b/include/sepol/roles.h
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_ROLES_H_
+#define _SEPOL_ROLES_H_
+
+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);
+
+#endif
diff --git a/include/sepol/sepol.h b/include/sepol/sepol.h
new file mode 100644
index 0000000..c8900d3
--- /dev/null
+++ b/include/sepol/sepol.h
@@ -0,0 +1,28 @@
+#ifndef _SEPOL_H_
+#define _SEPOL_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#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);
+
+#endif
diff --git a/include/sepol/user_record.h b/include/sepol/user_record.h
new file mode 100644
index 0000000..c86ad16
--- /dev/null
+++ b/include/sepol/user_record.h
@@ -0,0 +1,76 @@
+#ifndef _SEPOL_USER_RECORD_H_
+#define _SEPOL_USER_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+
+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);
+
+#endif
diff --git a/include/sepol/users.h b/include/sepol/users.h
new file mode 100644
index 0000000..01b0775
--- /dev/null
+++ b/include/sepol/users.h
@@ -0,0 +1,57 @@
+#ifndef _SEPOL_USERS_H_
+#define _SEPOL_USERS_H_
+
+#include <sepol/policydb.h>
+#include <sepol/user_record.h>
+#include <sepol/handle.h>
+#include <stddef.h>
+
+/*---------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);
+
+#endif
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 0000000..b96bc94
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,10 @@
+# Installation directories.
+MAN8DIR ?= $(DESTDIR)/usr/share/man/man8
+MAN3DIR ?= $(DESTDIR)/usr/share/man/man3
+
+install:
+	mkdir -p $(MAN3DIR)
+	mkdir -p $(MAN8DIR)
+	install -m 644 man3/*.3 $(MAN3DIR)
+	install -m 644 man8/*.8 $(MAN8DIR)
+
diff --git a/man/man3/sepol_check_context.3 b/man/man3/sepol_check_context.3
new file mode 100644
index 0000000..a63cd56
--- /dev/null
+++ b/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/man/man3/sepol_genbools.3 b/man/man3/sepol_genbools.3
new file mode 100644
index 0000000..0a30137
--- /dev/null
+++ b/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/man/man3/sepol_genusers.3 b/man/man3/sepol_genusers.3
new file mode 100644
index 0000000..05dff00
--- /dev/null
+++ b/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/man/man8/chkcon.8 b/man/man8/chkcon.8
new file mode 100644
index 0000000..f8d75df
--- /dev/null
+++ b/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/man/man8/genpolbools.8 b/man/man8/genpolbools.8
new file mode 100644
index 0000000..afeaced
--- /dev/null
+++ b/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/man/man8/genpolusers.8 b/man/man8/genpolusers.8
new file mode 100644
index 0000000..34d729a
--- /dev/null
+++ b/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/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..73fdef8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,56 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCLUDEDIR ?= $(PREFIX)/include
+LIBDIR ?= $(PREFIX)/lib
+SHLIBDIR ?= $(DESTDIR)/lib
+LIBBASE=$(shell basename $(LIBDIR))
+
+VERSION = $(shell cat ../VERSION)
+LIBVERSION = 1
+
+LIBA=libsepol.a 
+TARGET=libsepol.so
+LIBPC=libsepol.pc
+LIBSO=$(TARGET).$(LIBVERSION)
+OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
+LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
+CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-noreturn -Wmissing-format-attribute
+override CFLAGS += -I. -I../include -D_GNU_SOURCE
+
+all: $(LIBA) $(LIBSO) $(LIBPC)
+
+$(LIBA):  $(OBJS)
+	$(AR) rcs $@ $^
+	ranlib $@
+
+$(LIBSO): $(LOBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname,$(LIBSO),--version-script=libsepol.map,-z,defs
+	ln -sf $@ $(TARGET) 
+
+$(LIBPC): $(LIBPC).in
+	sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@
+
+%.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
+	cd $(LIBDIR) && ln -sf ../../`basename $(SHLIBDIR)`/$(LIBSO) $(TARGET)
+
+relabel:
+	/sbin/restorecon $(SHLIBDIR)/$(LIBSO)
+
+clean: 
+	-rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET)
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
diff --git a/src/assertion.c b/src/assertion.c
new file mode 100644
index 0000000..a6e0c04
--- /dev/null
+++ b/src/assertion.c
@@ -0,0 +1,151 @@
+/* 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 "debug.h"
+
+static int check_assertion_helper(sepol_handle_t * handle,
+				  policydb_t * p,
+				  avtab_t * te_avtab, avtab_t * te_cond_avtab,
+				  unsigned int stype, unsigned int ttype,
+				  class_perm_node_t * perm, unsigned long line)
+{
+	avtab_key_t avkey;
+	avtab_ptr_t node;
+	class_perm_node_t *curperm;
+
+	for (curperm = perm; curperm != NULL; curperm = curperm->next) {
+		avkey.source_type = stype + 1;
+		avkey.target_type = ttype + 1;
+		avkey.target_class = curperm->class;
+		avkey.specified = AVTAB_ALLOWED;
+		for (node = avtab_search_node(te_avtab, &avkey);
+		     node != NULL;
+		     node = avtab_search_node_next(node, avkey.specified)) {
+			if (node->datum.data & curperm->data)
+				goto err;
+		}
+		for (node = avtab_search_node(te_cond_avtab, &avkey);
+		     node != NULL;
+		     node = avtab_search_node_next(node, avkey.specified)) {
+			if (node->datum.data & curperm->data)
+				goto err;
+		}
+	}
+
+	return 0;
+
+      err:
+	if (line) {
+		ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
+		    line, p->p_type_val_to_name[stype], 
+		    p->p_type_val_to_name[ttype],
+		    p->p_class_val_to_name[curperm->class - 1],
+		    sepol_av_to_string(p, curperm->class,
+				       node->datum.data & curperm->data));
+	} 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->class - 1],
+		    sepol_av_to_string(p, curperm->class,
+				       node->datum.data & curperm->data));
+	}
+	return -1;
+}
+
+int check_assertions(sepol_handle_t * handle, policydb_t * p,
+		     avrule_t * avrules)
+{
+	avrule_t *a;
+	avtab_t te_avtab, te_cond_avtab;
+	ebitmap_node_t *snode, *tnode;
+	unsigned int i, j;
+	int rc;
+
+	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;
+	}
+
+	if (avrules) {
+		if (avtab_init(&te_avtab))
+			goto oom;
+		if (avtab_init(&te_cond_avtab)) {
+			avtab_destroy(&te_avtab);
+			goto oom;
+		}
+		if (expand_avtab(p, &p->te_avtab, &te_avtab) ||
+		    expand_avtab(p, &p->te_cond_avtab, &te_cond_avtab)) {
+			avtab_destroy(&te_avtab);
+			avtab_destroy(&te_cond_avtab);
+			goto oom;
+		}
+	}
+
+	for (a = avrules; a != NULL; a = a->next) {
+		ebitmap_t *stypes = &a->stypes.types;
+		ebitmap_t *ttypes = &a->ttypes.types;
+
+		if (!(a->specified & AVRULE_NEVERALLOW))
+			continue;
+
+		ebitmap_for_each_bit(stypes, snode, i) {
+			if (!ebitmap_node_get_bit(snode, i))
+				continue;
+			if (a->flags & RULE_SELF) {
+				if (check_assertion_helper
+				    (handle, p, &te_avtab, &te_cond_avtab, i, i,
+				     a->perms, a->line)) {
+					rc = -1;
+					goto out;
+				}
+			}
+			ebitmap_for_each_bit(ttypes, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+				if (check_assertion_helper
+				    (handle, p, &te_avtab, &te_cond_avtab, i, j,
+				     a->perms, a->line)) {
+					rc = -1;
+					goto out;
+				}
+			}
+		}
+	}
+
+	rc = 0;
+out:
+	avtab_destroy(&te_avtab);
+	avtab_destroy(&te_cond_avtab);
+	return rc;
+
+      oom:
+	ERR(handle, "Out of memory - unable to check neverallows");
+	return -1;
+}
diff --git a/src/av_permissions.h b/src/av_permissions.h
new file mode 100644
index 0000000..97278ed
--- /dev/null
+++ b/src/av_permissions.h
@@ -0,0 +1,3 @@
+/* Used by security_compute_av. */
+#define PROCESS__TRANSITION                       0x00000002UL
+#define PROCESS__DYNTRANSITION                    0x00800000UL
diff --git a/src/avrule_block.c b/src/avrule_block.c
new file mode 100644
index 0000000..16c89f3
--- /dev/null
+++ b/src/avrule_block.c
@@ -0,0 +1,202 @@
+/* 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);
+			free(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/src/avtab.c b/src/avtab.c
new file mode 100644
index 0000000..ea947cb
--- /dev/null
+++ b/src/avtab.c
@@ -0,0 +1,531 @@
+
+/* 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"
+
+static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask)
+{
+	return ((keyp->target_class + (keyp->target_type << 2) +
+		 (keyp->source_type << 9)) & 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;
+	newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
+	if (newnode == NULL)
+		return NULL;
+	memset(newnode, 0, sizeof(struct avtab_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 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))
+			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) {
+			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)
+{
+	uint16_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_SIZE)
+		nslot = MAX_AVTAB_SIZE;
+	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
+};
+
+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)
+{
+	uint16_t buf16[4], enabled;
+	uint32_t buf32[7], items, items2, val;
+	avtab_key_t key;
+	avtab_datum_t datum;
+	unsigned set;
+	unsigned int i;
+	int rc;
+
+	memset(&key, 0, sizeof(avtab_key_t));
+	memset(&datum, 0, sizeof(avtab_datum_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;
+	}
+
+	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/src/boolean_internal.h b/src/boolean_internal.h
new file mode 100644
index 0000000..aad7ade
--- /dev/null
+++ b/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/src/boolean_record.c b/src/boolean_record.c
new file mode 100644
index 0000000..8b64413
--- /dev/null
+++ b/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/src/booleans.c b/src/booleans.c
new file mode 100644
index 0000000..03f8c98
--- /dev/null
+++ b/src/booleans.c
@@ -0,0 +1,216 @@
+#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;
+
+	handle = NULL;
+	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/src/conditional.c b/src/conditional.c
new file mode 100644
index 0000000..1482387
--- /dev/null
+++ b/src/conditional.c
@@ -0,0 +1,905 @@
+/* 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;
+	}
+
+	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
+		   __attribute__ ((unused)), 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 (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;
+	}
+
+	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/src/constraint.c b/src/constraint.c
new file mode 100644
index 0000000..7154019
--- /dev/null
+++ b/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/src/context.c b/src/context.c
new file mode 100644
index 0000000..84dad34
--- /dev/null
+++ b/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/src/context.h b/src/context.h
new file mode 100644
index 0000000..d25ca8a
--- /dev/null
+++ b/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/src/context_internal.h b/src/context_internal.h
new file mode 100644
index 0000000..7987c1c
--- /dev/null
+++ b/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/src/context_record.c b/src/context_record.c
new file mode 100644
index 0000000..ac2884a
--- /dev/null
+++ b/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/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..51918fd
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,89 @@
+#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");
+
+	varg = NULL;
+}
+
+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/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..56b397b
--- /dev/null
+++ b/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/src/dso.h b/src/dso.h
new file mode 100644
index 0000000..5c69aae
--- /dev/null
+++ b/src/dso.h
@@ -0,0 +1,23 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H	1
+
+#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/src/ebitmap.c b/src/ebitmap.c
new file mode 100644
index 0000000..cc6a915
--- /dev/null
+++ b/src/ebitmap.c
@@ -0,0 +1,368 @@
+
+/* 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_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_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/src/expand.c b/src/expand.c
new file mode 100644
index 0000000..b42acbe
--- /dev/null
+++ b/src/expand.c
@@ -0,0 +1,3179 @@
+/* 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(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) {
+					/* 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_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++;
+
+	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 (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!");
+			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]);
+	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 associate with "
+				    "level %s",
+				    p->p_cat_val_to_name[i],
+				    p->p_sens_val_to_name[l->sens - 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!");
+			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 (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;
+
+	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) {
+						if ((cur_trans->role ==
+								i + 1) &&
+						    (cur_trans->type ==
+								j + 1) &&
+						    (cur_trans->tclass ==
+								k + 1)) {
+							if (cur_trans->
+							    new_role ==
+								cur->new_role) {
+								break;
+							} else {
+								ERR(state->handle,
+									"Conflicting role trans rule %s %s : %s %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[cur->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, *tail, *cur_trans;
+	filename_trans_rule_t *cur_rule;
+	ebitmap_t stypes, ttypes;
+	ebitmap_node_t *snode, *tnode;
+
+	/* start at the end of the list */
+	tail = state->out->filename_trans;
+	while (tail && tail->next)
+		tail = tail->next;
+
+	cur_rule = rules;
+	while (cur_rule) {
+		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;
+		}
+
+		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 == cur_rule->otype)
+							break;
+
+						ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s",
+						    cur_trans->name,
+						    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],
+						    state->out->p_type_val_to_name[cur_trans->otype - 1],
+						    state->out->p_type_val_to_name[state->typemap[cur_rule->otype - 1] - 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));
+				if (tail)
+					tail->next = new_trans;
+				else
+					state->out->filename_trans = new_trans;
+				tail = 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 = state->typemap[cur_rule->otype - 1];
+			}
+		}
+
+		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)
+{
+	avtab_ptr_t node;
+	avtab_datum_t avdatum;
+	cond_av_list_t *nl;
+
+	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->class;
+		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);
+		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)
+{
+	avtab_key_t avkey;
+	avtab_datum_t *avdatump;
+	avtab_ptr_t node;
+	class_perm_node_t *cur;
+	uint32_t spec = 0;
+
+	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 {
+		assert(0);	/* unreachable */
+	}
+
+	cur = perms;
+	while (cur) {
+		avkey.source_type = stype + 1;
+		avkey.target_type = ttype + 1;
+		avkey.target_class = cur->class;
+		avkey.specified = spec;
+
+		node = find_avtab_node(handle, avtab, &avkey, cond);
+		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 {
+			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) {
+				if ((retval =
+				     expand_avrule_helper(handle,
+							  source_rule->
+							  specified, cond, i, i,
+							  source_rule->perms,
+							  dest_avtab,
+							  enabled)) !=
+				    EXPAND_RULE_SUCCESS) {
+					return retval;
+				}
+			} else {
+				if ((retval =
+				     expand_terule_helper(handle, p,
+							  typemap,
+							  source_rule->
+							  specified, cond,
+							  other, i, i,
+							  source_rule->perms,
+							  dest_avtab,
+							  enabled)) !=
+				    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) {
+				if ((retval =
+				     expand_avrule_helper(handle,
+							  source_rule->
+							  specified, cond, i, j,
+							  source_rule->perms,
+							  dest_avtab,
+							  enabled)) !=
+				    EXPAND_RULE_SUCCESS) {
+					return retval;
+				}
+			} else {
+				if ((retval =
+				     expand_terule_helper(handle, p,
+							  typemap,
+							  source_rule->
+							  specified, cond,
+							  other, i, j,
+							  source_rule->perms,
+							  dest_avtab,
+							  enabled)) !=
+				    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;
+
+	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 (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)) {
+		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;
+			if (context_copy(&n->context[0], &c->context[0],
+				state)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			switch (i) {
+			case OCON_XEN_ISID:
+				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;
+			default:
+				/* shouldn't get here */
+				ERR(state->handle, "Unknown ocontext");
+				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;
+			if (context_copy(&n->context[0], &c->context[0], state)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+			switch (i) {
+			case OCON_ISID:
+				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;
+			}
+		}
+	}
+	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) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+
+		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!");
+				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;
+		}
+		if (!end) {
+			state->out->genfs = newgenfs;
+		} else {
+			end->next = newgenfs;
+		}
+		end = newgenfs;
+	}
+	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;
+
+	type = (type_datum_t *) datum;
+	if (type->flavor == TYPE_ATTRIB) {
+		if (ebitmap_cpy(&p->attr_type_map[type->s.value - 1],
+				&type->types)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		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],
+					    type->s.value - 1, 1)) {
+				ERR(state->handle, "Out of memory!");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+/* 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)
+		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;
+
+	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 = AVRULE_NEVERALLOW;
+	avrule->line = source_rule->line;
+	avrule->flags = source_rule->flags;
+
+	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->class = cur_perm->class;
+		assert(new_perm->class);
+
+		/* 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;
+	}
+
+	/* 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(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) {
+				/* 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) {
+					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);
+}
+
+/* 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;
+
+	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;
+		if (hashtab_map
+		    (decl->p_roles.table, role_fix_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);
+	evaluate_conds(state.out);
+
+	/* 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;
+	int rc;
+
+	node = avtab_search_node(a, k);
+	if (!node) {
+		rc = avtab_insert(a, k, d);
+		if (rc)
+			ERR(NULL, "Out of memory!");
+		return rc;
+	}
+
+	if ((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;
+	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;
+}
+
+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) {
+		/* Both are individual types, no expansion required. */
+		return expand_avtab_insert(expa, k, d);
+	}
+
+	if (stype) {
+		/* 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) {
+		/* 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) {
+		/* Both are individual types, no expansion required. */
+		return expand_cond_insert(newl, expa, k, d);
+	}
+
+	if (stype) {
+		/* 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) {
+		/* 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/src/genbools.c b/src/genbools.c
new file mode 100644
index 0000000..e353ef3
--- /dev/null
+++ b/src/genbools.c
@@ -0,0 +1,252 @@
+#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;
+	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;
+
+	while (getline(&buffer, &size, boolf) > 0) {
+		int ret = process_boolean(buffer, name, sizeof(name), &val);
+		if (ret == -1)
+			errors++;
+		if (ret == 1) {
+			datum = hashtab_search(policydb->p_bools.table, name);
+			if (!datum) {
+				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) {
+		while (getline(&buffer, &size, boolf) > 0) {
+			int ret =
+			    process_boolean(buffer, name, sizeof(name), &val);
+			if (ret == -1)
+				errors++;
+			if (ret == 1) {
+				datum =
+				    hashtab_search(policydb->p_bools.table,
+						   name);
+				if (!datum) {
+					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/src/genusers.c b/src/genusers.c
new file mode 100644
index 0000000..44f94e9
--- /dev/null
+++ b/src/genusers.c
@@ -0,0 +1,318 @@
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sepol/policydb/policydb.h>
+#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;
+	__fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+	while ((nread = getline(&buffer, &len, fp)) > 0) {
+		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);
+
+			/* Adding a new user definition. */
+			usrdatum =
+			    (user_datum_t *) malloc(sizeof(user_datum_t));
+			if (!id || !usrdatum) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				fclose(fp);
+				return -1;
+			}
+			memset(usrdatum, 0, sizeof(user_datum_t));
+			usrdatum->s.value = ++policydb->p_users.nprim;
+			ebitmap_init(&usrdatum->roles.roles);
+			if (hashtab_insert(policydb->p_users.table,
+					   id, (hashtab_datum_t) usrdatum)) {
+				ERR(NULL, "out of memory");
+				free(buffer);
+				fclose(fp);
+				return -1;
+			}
+		}
+
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		if (strncasecmp(p, "roles", 5))
+			BADLINE();
+		p += 5;
+		if (!isspace(*p))
+			BADLINE();
+		while (*p && isspace(*p))
+			p++;
+		if (!(*p))
+			BADLINE();
+		if (*p == '{') {
+			islist = 1;
+			p++;
+		} else
+			islist = 0;
+
+		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/src/handle.c b/src/handle.c
new file mode 100644
index 0000000..191ac57
--- /dev/null
+++ b/src/handle.c
@@ -0,0 +1,45 @@
+#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;
+
+	return sh;
+}
+
+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/src/handle.h b/src/handle.h
new file mode 100644
index 0000000..254fbd8
--- /dev/null
+++ b/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;
+
+};
+
+#endif
diff --git a/src/hashtab.c b/src/hashtab.c
new file mode 100644
index 0000000..c4be72c
--- /dev/null
+++ b/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/src/hierarchy.c b/src/hierarchy.c
new file mode 100644
index 0000000..e2df5a4
--- /dev/null
+++ b/src/hierarchy.c
@@ -0,0 +1,501 @@
+/* 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"
+
+typedef struct hierarchy_args {
+	policydb_t *p;
+	avtab_t *expa;		/* expanded avtab */
+	/* This tells check_avtab_hierarchy to check this list in addition to the unconditional avtab */
+	cond_av_list_t *opt_cond_list;
+	sepol_handle_t *handle;
+	int numerr;
+} hierarchy_args_t;
+
+/*
+ * find_parent_(type|role|user)
+ *
+ * This function returns the parent datum of given XXX_datum_t
+ * object or NULL, if it doesn't exist.
+ *
+ * If the given datum has a valid bounds, this function merely
+ * returns the indicated object. Otherwise, it looks up the
+ * parent based on the based hierarchy.
+ */
+#define find_parent_template(prefix)				\
+int find_parent_##prefix(hierarchy_args_t *a,			\
+			 prefix##_datum_t *datum,		\
+			 prefix##_datum_t **parent)		\
+{								\
+	char *parent_name, *datum_name, *tmp;			\
+								\
+	if (datum->bounds)						\
+		*parent = a->p->prefix##_val_to_struct[datum->bounds - 1]; \
+	else {								\
+		datum_name = a->p->p_##prefix##_val_to_name[datum->s.value - 1]; \
+									\
+		tmp = strrchr(datum_name, '.');				\
+		/* no '.' means it has no parent */			\
+		if (!tmp) {						\
+			*parent = NULL;					\
+			return 0;					\
+		}							\
+									\
+		parent_name = strdup(datum_name);			\
+		if (!parent_name)					\
+			return -1;					\
+		parent_name[tmp - datum_name] = '\0';			\
+									\
+		*parent = hashtab_search(a->p->p_##prefix##s.table, parent_name); \
+		if (!*parent) {						\
+			/* Orphan type/role/user */			\
+			ERR(a->handle,					\
+			    "%s doesn't exist, %s is an orphan",	\
+			    parent_name,				\
+			    a->p->p_##prefix##_val_to_name[datum->s.value - 1]); \
+			free(parent_name);				\
+			return -1;					\
+		}							\
+		free(parent_name);					\
+	}								\
+									\
+	return 0;							\
+}
+
+static find_parent_template(type)
+static find_parent_template(role)
+static find_parent_template(user)
+
+static void compute_avtab_datum(hierarchy_args_t *args,
+				avtab_key_t *key,
+				avtab_datum_t *result)
+{
+	avtab_datum_t *avdatp;
+	uint32_t av = 0;
+
+	avdatp = avtab_search(args->expa, key);
+	if (avdatp)
+		av = avdatp->data;
+	if (args->opt_cond_list) {
+		avdatp = cond_av_list_search(key, args->opt_cond_list);
+		if (avdatp)
+			av |= avdatp->data;
+	}
+
+	result->data = av;
+}
+
+/* This function verifies that the type passed in either has a parent or is in the 
+ * root of the namespace, 0 on success, 1 on orphan and -1 on error
+ */
+static int check_type_hierarchy_callback(hashtab_key_t k, hashtab_datum_t d,
+					 void *args)
+{
+	hierarchy_args_t *a;
+	type_datum_t *t, *tp;
+
+	a = (hierarchy_args_t *) args;
+	t = (type_datum_t *) d;
+
+	if (t->flavor == TYPE_ATTRIB) {
+		/* It's an attribute, we don't care */
+		return 0;
+	}
+	if (find_parent_type(a, t, &tp) < 0)
+		return -1;
+
+	if (tp && tp->flavor == TYPE_ATTRIB) {
+		/* The parent is an attribute but the child isn't, not legal */
+		ERR(a->handle, "type %s is a child of an attribute %s",
+		    (char *) k, a->p->p_type_val_to_name[tp->s.value - 1]);
+		a->numerr++;
+		return -1;
+	}
+	return 0;
+}
+
+/* This function only verifies that the avtab node passed in does not violate any
+ * hiearchy constraint via any relationship with other types in the avtab.
+ * it should be called using avtab_map, returns 0 on success, 1 on violation and
+ * -1 on error. opt_cond_list is an optional argument that tells this to check
+ * a conditional list for the relationship as well as the unconditional avtab
+ */
+static int check_avtab_hierarchy_callback(avtab_key_t * k, avtab_datum_t * d,
+					  void *args)
+{
+	avtab_key_t key;
+	hierarchy_args_t *a = (hierarchy_args_t *) args;
+	type_datum_t *s, *t1 = NULL, *t2 = NULL;
+	avtab_datum_t av;
+
+	if (!(k->specified & AVTAB_ALLOWED)) {
+		/* This is not an allow rule, no checking done */
+		return 0;
+	}
+
+	/* search for parent first */
+	s = a->p->type_val_to_struct[k->source_type - 1];
+	if (find_parent_type(a, s, &t1) < 0)
+		return -1;
+	if (t1) {
+		/*
+		 * search for access allowed between type 1's
+		 * parent and type 2.
+		 */
+		key.source_type = t1->s.value;
+		key.target_type = k->target_type;
+		key.target_class = k->target_class;
+		key.specified = AVTAB_ALLOWED;
+		compute_avtab_datum(a, &key, &av);
+
+		if ((av.data & d->data) == d->data)
+			return 0;
+	}
+
+	/* next we try type 1 and type 2's parent */
+	s = a->p->type_val_to_struct[k->target_type - 1];
+	if (find_parent_type(a, s, &t2) < 0)
+		return -1;
+	if (t2) {
+		/*
+		 * search for access allowed between type 1 and
+		 * type 2's parent.
+		 */
+		key.source_type = k->source_type;
+		key.target_type = t2->s.value;
+		key.target_class = k->target_class;
+		key.specified = AVTAB_ALLOWED;
+		compute_avtab_datum(a, &key, &av);
+
+		if ((av.data & d->data) == d->data)
+			return 0;
+	}
+
+	if (t1 && t2) {
+		/*
+                 * search for access allowed between type 1's parent
+                 * and type 2's parent.
+                 */
+		key.source_type = t1->s.value;
+		key.target_type = t2->s.value;
+		key.target_class = k->target_class;
+		key.specified = AVTAB_ALLOWED;
+		compute_avtab_datum(a, &key, &av);
+
+		if ((av.data & d->data) == d->data)
+			return 0;
+	}
+
+	/*
+	 * Neither one of these types have parents and 
+	 * therefore the hierarchical constraint does not apply
+	 */
+	if (!t1 && !t2)
+		return 0;
+
+	/*
+	 * At this point there is a violation of the hierarchal
+	 * constraint, send error condition back
+	 */
+	ERR(a->handle,
+	    "hierarchy violation between types %s and %s : %s { %s }",
+	    a->p->p_type_val_to_name[k->source_type - 1],
+	    a->p->p_type_val_to_name[k->target_type - 1],
+	    a->p->p_class_val_to_name[k->target_class - 1],
+	    sepol_av_to_string(a->p, k->target_class, d->data & ~av.data));
+	a->numerr++;
+	return 0;
+}
+
+/*
+ * If same permissions are allowed for same combination of
+ * source and target, we can evaluate them as unconditional
+ * one.
+ * See the following example. A_t type is bounds of B_t type,
+ * so B_t can never have wider permissions then A_t.
+ * A_t has conditional permission on X_t, however, a part of
+ * them (getattr and read) are unconditionaly allowed to A_t.
+ *
+ * Example)
+ * typebounds A_t B_t;
+ *
+ * allow B_t X_t : file { getattr };
+ * if (foo_bool) {
+ *     allow A_t X_t : file { getattr read };
+ * } else {
+ *     allow A_t X_t : file { getattr read write };
+ * }
+ *
+ * We have to pull up them as unconditional ones in this case,
+ * because it seems to us B_t is violated to bounds constraints
+ * during unconditional policy checking.
+ */
+static int pullup_unconditional_perms(cond_list_t * cond_list,
+				      hierarchy_args_t * args)
+{
+	cond_list_t *cur_node;
+	cond_av_list_t *cur_av, *expl_true = NULL, *expl_false = NULL;
+	avtab_t expa_true, expa_false;
+	avtab_datum_t *avdatp;
+	avtab_datum_t avdat;
+	avtab_ptr_t avnode;
+
+	for (cur_node = cond_list; cur_node; cur_node = cur_node->next) {
+		if (avtab_init(&expa_true))
+			goto oom0;
+		if (avtab_init(&expa_false))
+			goto oom1;
+		if (expand_cond_av_list(args->p, cur_node->true_list,
+					&expl_true, &expa_true))
+			goto oom2;
+		if (expand_cond_av_list(args->p, cur_node->false_list,
+					&expl_false, &expa_false))
+			goto oom3;
+		for (cur_av = expl_true; cur_av; cur_av = cur_av->next) {
+			avdatp = avtab_search(&expa_false,
+					      &cur_av->node->key);
+			if (!avdatp)
+				continue;
+
+			avdat.data = (cur_av->node->datum.data
+				      & avdatp->data);
+			if (!avdat.data)
+				continue;
+
+			avnode = avtab_search_node(args->expa,
+						   &cur_av->node->key);
+			if (avnode) {
+				avnode->datum.data |= avdat.data;
+			} else {
+				if (avtab_insert(args->expa,
+						 &cur_av->node->key,
+						 &avdat))
+					goto oom4;
+			}
+		}
+		cond_av_list_destroy(expl_false);
+		cond_av_list_destroy(expl_true);
+		avtab_destroy(&expa_false);
+		avtab_destroy(&expa_true);
+	}
+	return 0;
+
+oom4:
+	cond_av_list_destroy(expl_false);
+oom3:
+	cond_av_list_destroy(expl_true);
+oom2:
+	avtab_destroy(&expa_false);
+oom1:
+	avtab_destroy(&expa_true);
+oom0:
+	ERR(args->handle, "out of memory on conditional av list expansion");
+        return 1;
+}
+
+static int check_cond_avtab_hierarchy(cond_list_t * cond_list,
+				      hierarchy_args_t * args)
+{
+	int rc;
+	cond_list_t *cur_node;
+	cond_av_list_t *cur_av, *expl = NULL;
+	avtab_t expa;
+	hierarchy_args_t *a = (hierarchy_args_t *) args;
+	avtab_datum_t avdat, *uncond;
+
+	for (cur_node = cond_list; cur_node; cur_node = cur_node->next) {
+		/*
+		 * Check true condition
+		 */
+		if (avtab_init(&expa))
+			goto oom;
+		if (expand_cond_av_list(args->p, cur_node->true_list,
+					&expl, &expa)) {
+			avtab_destroy(&expa);
+			goto oom;
+		}
+		args->opt_cond_list = expl;
+		for (cur_av = expl; cur_av; cur_av = cur_av->next) {
+			avdat.data = cur_av->node->datum.data;
+			uncond = avtab_search(a->expa, &cur_av->node->key);
+			if (uncond)
+				avdat.data |= uncond->data;
+			rc = check_avtab_hierarchy_callback(&cur_av->node->key,
+							    &avdat, args);
+			if (rc)
+				args->numerr++;
+		}
+		cond_av_list_destroy(expl);
+
+		/*
+		 * Check false condition
+		 */
+		if (avtab_init(&expa))
+			goto oom;
+		if (expand_cond_av_list(args->p, cur_node->false_list,
+					&expl, &expa)) {
+			avtab_destroy(&expa);
+			goto oom;
+		}
+		args->opt_cond_list = expl;
+		for (cur_av = expl; cur_av; cur_av = cur_av->next) {
+			avdat.data = cur_av->node->datum.data;
+			uncond = avtab_search(a->expa, &cur_av->node->key);
+			if (uncond)
+				avdat.data |= uncond->data;
+
+			rc = check_avtab_hierarchy_callback(&cur_av->node->key,
+							    &avdat, args);
+			if (rc)
+				a->numerr++;
+		}
+		cond_av_list_destroy(expl);
+		avtab_destroy(&expa);
+	}
+
+	return 0;
+
+      oom:
+	ERR(args->handle, "out of memory on conditional av list expansion");
+	return 1;
+}
+
+/* The role hierarchy is defined as: a child role cannot have more types than it's parent.
+ * This function should be called with hashtab_map, it will return 0 on success, 1 on 
+ * constraint violation and -1 on error
+ */
+static int check_role_hierarchy_callback(hashtab_key_t k
+					 __attribute__ ((unused)),
+					 hashtab_datum_t d, void *args)
+{
+	hierarchy_args_t *a;
+	role_datum_t *r, *rp;
+
+	a = (hierarchy_args_t *) args;
+	r = (role_datum_t *) d;
+
+	if (find_parent_role(a, r, &rp) < 0)
+		return -1;
+
+	if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
+		/* hierarchical constraint violation, return error */
+		ERR(a->handle, "Role hierarchy violation, %s exceeds %s",
+		    (char *) k, a->p->p_role_val_to_name[rp->s.value - 1]);
+		a->numerr++;
+	}
+	return 0;
+}
+
+/* The user hierarchy is defined as: a child user cannot have a role that
+ * its parent doesn't have.  This function should be called with hashtab_map,
+ * it will return 0 on success, 1 on constraint violation and -1 on error.
+ */
+static int check_user_hierarchy_callback(hashtab_key_t k
+					 __attribute__ ((unused)),
+					 hashtab_datum_t d, void *args)
+{
+	hierarchy_args_t *a;
+	user_datum_t *u, *up;
+
+	a = (hierarchy_args_t *) args;
+	u = (user_datum_t *) d;
+
+	if (find_parent_user(a, u, &up) < 0)
+		return -1;
+
+	if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
+		/* hierarchical constraint violation, return error */
+		ERR(a->handle, "User hierarchy violation, %s exceeds %s",
+		    (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
+		a->numerr++;
+	}
+	return 0;
+}
+
+int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
+{
+	hierarchy_args_t args;
+	avtab_t expa;
+
+	if (avtab_init(&expa))
+		goto oom;
+	if (expand_avtab(p, &p->te_avtab, &expa)) {
+		avtab_destroy(&expa);
+		goto oom;
+	}
+
+	args.p = p;
+	args.expa = &expa;
+	args.opt_cond_list = NULL;
+	args.handle = handle;
+	args.numerr = 0;
+
+	if (hashtab_map(p->p_types.table, check_type_hierarchy_callback, &args))
+		goto bad;
+
+	if (pullup_unconditional_perms(p->cond_list, &args))
+		return -1;
+
+	if (avtab_map(&expa, check_avtab_hierarchy_callback, &args))
+		goto bad;
+
+	if (check_cond_avtab_hierarchy(p->cond_list, &args))
+		goto bad;
+
+	if (hashtab_map(p->p_roles.table, check_role_hierarchy_callback, &args))
+		goto bad;
+
+	if (hashtab_map(p->p_users.table, check_user_hierarchy_callback, &args))
+		goto bad;
+
+	if (args.numerr) {
+		ERR(handle, "%d total errors found during hierarchy check",
+		    args.numerr);
+		goto bad;
+	}
+
+	avtab_destroy(&expa);
+	return 0;
+
+      bad:
+	avtab_destroy(&expa);
+	return -1;
+
+      oom:
+	ERR(handle, "Out of memory");
+	return -1;
+}
diff --git a/src/iface_internal.h b/src/iface_internal.h
new file mode 100644
index 0000000..5b78d9b
--- /dev/null
+++ b/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/src/iface_record.c b/src/iface_record.c
new file mode 100644
index 0000000..09adeb7
--- /dev/null
+++ b/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/src/interfaces.c b/src/interfaces.c
new file mode 100644
index 0000000..b82d0f3
--- /dev/null
+++ b/src/interfaces.c
@@ -0,0 +1,273 @@
+#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;
+
+	handle = NULL;
+	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;
+
+	handle = NULL;
+	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/src/libsepol.map b/src/libsepol.map
new file mode 100644
index 0000000..719e5b7
--- /dev/null
+++ b/src/libsepol.map
@@ -0,0 +1,19 @@
+{
+  global: 
+	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;
+  local: *;
+};
diff --git a/src/libsepol.pc.in b/src/libsepol.pc.in
new file mode 100644
index 0000000..e52f589
--- /dev/null
+++ b/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/src/link.c b/src/link.c
new file mode 100644
index 0000000..421c47b
--- /dev/null
+++ b/src/link.c
@@ -0,0 +1,2598 @@
+/* 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_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");
+				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");
+				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;
+
+	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;
+
+	}
+
+	/* 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;
+
+	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;
+		}
+		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;
+		}
+	}
+
+	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;
+		}
+		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;
+		}
+	}
+
+	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->class =
+			    module->map[SYM_CLASSES][cur_perm->class - 1];
+			assert(new_perm->class);
+
+			if (new_rule->specified & AVRULE_AV) {
+				for (i = 0;
+				     i <
+				     module->perm_map_len[cur_perm->class - 1];
+				     i++) {
+					if (!(cur_perm->data & (1U << i)))
+						continue;
+					new_perm->data |=
+					    (1U <<
+					     (module->
+					      perm_map[cur_perm->class - 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 {
+				tail_perm->next = new_perm;
+			}
+			tail_perm = new_perm;
+			cur_perm = cur_perm->next;
+		}
+		new_rule->line = cur->line;
+
+		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");
+				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) {
+			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;
+			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;
+
+			hashtab_map(cladatum->permissions.table, find_perm,
+				    &fparg);
+			if (fparg.key == NULL && cladatum->comdatum != NULL)
+				hashtab_map(cladatum->comdatum->permissions.
+					    table, find_perm, &fparg);
+			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;
+
+	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) {
+			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;
+				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;
+	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;
+		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) {
+				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/src/mls.c b/src/mls.c
new file mode 100644
index 0000000..1e84bb7
--- /dev/null
+++ b/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/src/mls.h b/src/mls.h
new file mode 100644
index 0000000..98da3d3
--- /dev/null
+++ b/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/src/module.c b/src/module.c
new file mode 100644
index 0000000..b5b807e
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,985 @@
+/* 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 size_t policy_file_length(struct policy_file *fp)
+{
+	long prev_offset, end_offset;
+	switch (fp->type) {
+	case PF_USE_STDIO:
+		prev_offset = ftell(fp->fp);
+		fseek(fp->fp, 0L, SEEK_END);
+		end_offset = ftell(fp->fp);
+		fseek(fp->fp, prev_offset, SEEK_SET);
+		return end_offset;
+	case PF_USE_MEMORY:
+		return fp->size;
+	default:
+		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)
+{
+	*p = calloc(1, sizeof(sepol_module_package_t));
+	if (!(*p))
+		return -1;
+	return module_package_init(*p);
+}
+
+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;
+		}
+	}
+
+	off[nsec] = policy_file_length(file);
+	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/src/module_internal.h b/src/module_internal.h
new file mode 100644
index 0000000..cdd5ec6
--- /dev/null
+++ b/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/src/node_internal.h b/src/node_internal.h
new file mode 100644
index 0000000..802cda9
--- /dev/null
+++ b/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/src/node_record.c b/src/node_record.c
new file mode 100644
index 0000000..b1bd370
--- /dev/null
+++ b/src/node_record.c
@@ -0,0 +1,668 @@
+#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;
+			}
+
+			memcpy(addr_bytes, in_addr.s6_addr32, 16);
+			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));
+			memcpy(&addr.s6_addr32[0], addr_bytes, 16);
+
+			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/src/nodes.c b/src/nodes.c
new file mode 100644
index 0000000..ebf5f1d
--- /dev/null
+++ b/src/nodes.c
@@ -0,0 +1,400 @@
+#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;
+
+	handle = NULL;
+	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/src/polcaps.c b/src/polcaps.c
new file mode 100644
index 0000000..71970b1
--- /dev/null
+++ b/src/polcaps.c
@@ -0,0 +1,33 @@
+/*
+ * 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 */
+	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/src/policydb.c b/src/policydb.c
new file mode 100644
index 0000000..53d0fda
--- /dev/null
+++ b/src/policydb.c
@@ -0,0 +1,3843 @@
+
+/* 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)
+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_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_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_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,
+	},
+};
+
+#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);
+
+	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;
+	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;
+	}
+	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)
+				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++) {
+		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++) {
+		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;
+				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 (hashtab_insert(h, key, cladatum))
+		goto bad;
+
+	return 0;
+
+      bad:
+	class_destroy(key, cladatum, NULL);
+	return -1;
+}
+
+static int role_read(policydb_t * p
+		     __attribute__ ((unused)), 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
+		     __attribute__ ((unused)), 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;
+		rc = next_entry(buf, fp, sizeof(uint32_t));
+		if (rc < 0)
+			return -1;
+		len = le32_to_cpu(buf[0]);
+
+		name = calloc(len, 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;
+	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:
+				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;
+			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->class = 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;
+
+	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 {
+				last_decl->next = curdecl;
+			}
+			last_decl = curdecl;
+			num_decls--;
+		}
+
+		if (*block == NULL) {
+			*block = curblock;
+		} else {
+			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;
+		}
+	}
+
+	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/src/policydb_convert.c b/src/policydb_convert.c
new file mode 100644
index 0000000..32832bb
--- /dev/null
+++ b/src/policydb_convert.c
@@ -0,0 +1,100 @@
+#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)) {
+		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/src/policydb_internal.h b/src/policydb_internal.h
new file mode 100644
index 0000000..8a31506
--- /dev/null
+++ b/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 char *policydb_target_strings[];
+#endif
diff --git a/src/policydb_public.c b/src/policydb_public.c
new file mode 100644
index 0000000..f6ae793
--- /dev/null
+++ b/src/policydb_public.c
@@ -0,0 +1,193 @@
+#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_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/src/port_internal.h b/src/port_internal.h
new file mode 100644
index 0000000..ffb5f65
--- /dev/null
+++ b/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/src/port_record.c b/src/port_record.c
new file mode 100644
index 0000000..6a33d93
--- /dev/null
+++ b/src/port_record.c
@@ -0,0 +1,288 @@
+#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";
+	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/src/ports.c b/src/ports.c
new file mode 100644
index 0000000..cbf2a0b
--- /dev/null
+++ b/src/ports.c
@@ -0,0 +1,312 @@
+#include <netinet/in.h>
+#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;
+	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;
+	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;
+
+	handle = NULL;
+	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/src/private.h b/src/private.h
new file mode 100644
index 0000000..b2b247e
--- /dev/null
+++ b/src/private.h
@@ -0,0 +1,49 @@
+/* Private definitions for libsepol. */
+
+/* Endian conversion for reading and writing binary policies */
+
+#include <sepol/policydb/policydb.h>
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <dso.h>
+
+#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))
+
+#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/src/roles.c b/src/roles.c
new file mode 100644
index 0000000..419a3b2
--- /dev/null
+++ b/src/roles.c
@@ -0,0 +1,55 @@
+#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);
+
+	handle = 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/src/services.c b/src/services.c
new file mode 100644
index 0000000..9c2920c
--- /dev/null
+++ b/src/services.c
@@ -0,0 +1,1469 @@
+
+/*
+ * 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.
+ */
+
+#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 "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;
+
+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)) {
+		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;
+
+/*
+ * 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 should pass in NULL for xcontext.
+ */
+static int constraint_expr_eval(context_struct_t * scontext,
+				context_struct_t * tcontext,
+				context_struct_t * xcontext,
+				constraint_expr_t * cexpr)
+{
+	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;
+
+	for (e = cexpr; e; e = e->next) {
+		switch (e->expr_type) {
+		case CEXPR_NOT:
+			BUG_ON(sp < 0);
+			s[sp] = !s[sp];
+			break;
+		case CEXPR_AND:
+			BUG_ON(sp < 1);
+			sp--;
+			s[sp] &= s[sp + 1];
+			break;
+		case CEXPR_OR:
+			BUG_ON(sp < 1);
+			sp--;
+			s[sp] |= s[sp + 1];
+			break;
+		case CEXPR_ATTR:
+			if (sp == (CEXPR_MAXDEPTH - 1))
+				return 0;
+			switch (e->attr) {
+			case CEXPR_USER:
+				val1 = scontext->user;
+				val2 = tcontext->user;
+				break;
+			case CEXPR_TYPE:
+				val1 = scontext->type;
+				val2 = tcontext->type;
+				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];
+				switch (e->op) {
+				case CEXPR_DOM:
+					s[++sp] =
+					    ebitmap_get_bit(&r1->dominates,
+							    val2 - 1);
+					continue;
+				case CEXPR_DOMBY:
+					s[++sp] =
+					    ebitmap_get_bit(&r2->dominates,
+							    val1 - 1);
+					continue;
+				case CEXPR_INCOMP:
+					s[++sp] =
+					    (!ebitmap_get_bit
+					     (&r1->dominates, val2 - 1)
+					     && !ebitmap_get_bit(&r2->dominates,
+								 val1 - 1));
+					continue;
+				default:
+					break;
+				}
+				break;
+			case CEXPR_L1L2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[0]);
+				goto mls_ops;
+			case CEXPR_L1H2:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_H1L2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[0]);
+				goto mls_ops;
+			case CEXPR_H1H2:
+				l1 = &(scontext->range.level[1]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_L1H1:
+				l1 = &(scontext->range.level[0]);
+				l2 = &(scontext->range.level[1]);
+				goto mls_ops;
+			case CEXPR_L2H2:
+				l1 = &(tcontext->range.level[0]);
+				l2 = &(tcontext->range.level[1]);
+				goto mls_ops;
+			      mls_ops:
+				switch (e->op) {
+				case CEXPR_EQ:
+					s[++sp] = mls_level_eq(l1, l2);
+					continue;
+				case CEXPR_NEQ:
+					s[++sp] = !mls_level_eq(l1, l2);
+					continue;
+				case CEXPR_DOM:
+					s[++sp] = mls_level_dom(l1, l2);
+					continue;
+				case CEXPR_DOMBY:
+					s[++sp] = mls_level_dom(l2, l1);
+					continue;
+				case CEXPR_INCOMP:
+					s[++sp] = mls_level_incomp(l2, l1);
+					continue;
+				default:
+					BUG();
+					return 0;
+				}
+				break;
+			default:
+				BUG();
+				return 0;
+			}
+
+			switch (e->op) {
+			case CEXPR_EQ:
+				s[++sp] = (val1 == val2);
+				break;
+			case CEXPR_NEQ:
+				s[++sp] = (val1 != val2);
+				break;
+			default:
+				BUG();
+				return 0;
+			}
+			break;
+		case CEXPR_NAMES:
+			if (sp == (CEXPR_MAXDEPTH - 1))
+				return 0;
+			c = scontext;
+			if (e->attr & CEXPR_TARGET)
+				c = tcontext;
+			else if (e->attr & CEXPR_XTARGET) {
+				c = xcontext;
+				if (!c) {
+					BUG();
+					return 0;
+				}
+			}
+			if (e->attr & CEXPR_USER)
+				val1 = c->user;
+			else if (e->attr & CEXPR_ROLE)
+				val1 = c->role;
+			else if (e->attr & CEXPR_TYPE)
+				val1 = c->type;
+			else {
+				BUG();
+				return 0;
+			}
+
+			switch (e->op) {
+			case CEXPR_EQ:
+				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+				break;
+			case CEXPR_NEQ:
+				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+				break;
+			default:
+				BUG();
+				return 0;
+			}
+			break;
+		default:
+			BUG();
+			return 0;
+		}
+	}
+
+	BUG_ON(sp != 0);
+	return s[0];
+}
+
+/*
+ * 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)
+{
+	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(scontext, tcontext, NULL,
+					  constraint->expr)) {
+			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(ocontext, ncontext, tcontext,
+					  constraint->expr)) {
+			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);
+      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);
+}
+
+/*
+ * 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)) {
+		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);
+			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,
+			   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/src/sidtab.c b/src/sidtab.c
new file mode 100644
index 0000000..5bd7999
--- /dev/null
+++ b/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/src/symtab.c b/src/symtab.c
new file mode 100644
index 0000000..b3a7aa8
--- /dev/null
+++ b/src/symtab.c
@@ -0,0 +1,49 @@
+
+/* 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;
+}
+
+/* FLASK */
diff --git a/src/user_internal.h b/src/user_internal.h
new file mode 100644
index 0000000..7523b7d
--- /dev/null
+++ b/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/src/user_record.c b/src/user_record.c
new file mode 100644
index 0000000..c59c54b
--- /dev/null
+++ b/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/src/users.c b/src/users.c
new file mode 100644
index 0000000..693210d
--- /dev/null
+++ b/src/users.c
@@ -0,0 +1,383 @@
+#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);
+
+	handle = 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;
+
+	handle = NULL;
+	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/src/util.c b/src/util.c
new file mode 100644
index 0000000..a824e61
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,116 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.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;
+}
diff --git a/src/write.c b/src/write.c
new file mode 100644
index 0000000..290e036
--- /dev/null
+++ b/src/write.c
@@ -0,0 +1,2009 @@
+
+/* 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;
+	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;
+	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;
+
+	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;
+	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;
+	}
+
+	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)) {
+					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;
+	}
+
+	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;
+
+	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;
+	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:
+				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;
+			}
+		}
+	}
+	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;
+
+	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->class);
+		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) {
+		avrule_write(avrule, fp);
+		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;
+
+	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... */
+		if ((dyn_buf = malloc(items * sizeof(*dyn_buf))) == NULL) {
+			return POLICYDB_ERROR;
+		}
+		buf = dyn_buf;
+	} else {
+		buf = static_buf;
+	}
+	buf[0] = cpu_to_le32(key_len);
+	if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
+	    put_entry(key, 1, key_len, fp) != key_len) {
+		return POLICYDB_ERROR;
+	}
+	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]);
+	}
+	if (put_entry(buf, sizeof(*buf), items, fp) != items) {
+		free(dyn_buf);
+		return POLICYDB_ERROR;
+	}
+	free(dyn_buf);
+	return POLICYDB_SUCCESS;
+}
+
+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;
+}
+
+/*
+ * 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;
+	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] = cpu_to_le32(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]);
+		}
+		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/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..dd7bd33
--- /dev/null
+++ b/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/tests/debug.c b/tests/debug.c
new file mode 100644
index 0000000..90aa6e0
--- /dev/null
+++ b/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/tests/debug.h b/tests/debug.h
new file mode 100644
index 0000000..c25ebd4
--- /dev/null
+++ b/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/tests/helpers.c b/tests/helpers.c
new file mode 100644
index 0000000..542e467
--- /dev/null
+++ b/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/tests/helpers.h b/tests/helpers.h
new file mode 100644
index 0000000..418ee95
--- /dev/null
+++ b/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/tests/libsepol-tests.c b/tests/libsepol-tests.c
new file mode 100644
index 0000000..9302f72
--- /dev/null
+++ b/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/tests/policies/support/misc_macros.spt b/tests/policies/support/misc_macros.spt
new file mode 100644
index 0000000..5fadd0f
--- /dev/null
+++ b/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/tests/policies/test-cond/refpolicy-base.conf b/tests/policies/test-cond/refpolicy-base.conf
new file mode 100644
index 0000000..60da11a
--- /dev/null
+++ b/tests/policies/test-cond/refpolicy-base.conf
@@ -0,0 +1,1939 @@
+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;
+	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/tests/policies/test-deps/base-metreq.conf b/tests/policies/test-deps/base-metreq.conf
new file mode 100644
index 0000000..9b7ade5
--- /dev/null
+++ b/tests/policies/test-deps/base-metreq.conf
@@ -0,0 +1,519 @@
+# 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;
+
+# 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/tests/policies/test-deps/base-notmetreq.conf b/tests/policies/test-deps/base-notmetreq.conf
new file mode 100644
index 0000000..cf6aa0a
--- /dev/null
+++ b/tests/policies/test-deps/base-notmetreq.conf
@@ -0,0 +1,506 @@
+# 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 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/tests/policies/test-deps/modreq-attr-global.conf b/tests/policies/test-deps/modreq-attr-global.conf
new file mode 100644
index 0000000..92f6b30
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-attr-opt.conf b/tests/policies/test-deps/modreq-attr-opt.conf
new file mode 100644
index 0000000..b970c1d
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-bool-global.conf b/tests/policies/test-deps/modreq-bool-global.conf
new file mode 100644
index 0000000..4ef0cc9
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-bool-opt.conf b/tests/policies/test-deps/modreq-bool-opt.conf
new file mode 100644
index 0000000..27af4f2
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-obj-global.conf b/tests/policies/test-deps/modreq-obj-global.conf
new file mode 100644
index 0000000..e9eba77
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-obj-opt.conf b/tests/policies/test-deps/modreq-obj-opt.conf
new file mode 100644
index 0000000..67a41a4
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-perm-global.conf b/tests/policies/test-deps/modreq-perm-global.conf
new file mode 100644
index 0000000..941ca96
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-perm-opt.conf b/tests/policies/test-deps/modreq-perm-opt.conf
new file mode 100644
index 0000000..43a3f97
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-role-global.conf b/tests/policies/test-deps/modreq-role-global.conf
new file mode 100644
index 0000000..01fd3ec
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-role-opt.conf b/tests/policies/test-deps/modreq-role-opt.conf
new file mode 100644
index 0000000..532a77e
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-type-global.conf b/tests/policies/test-deps/modreq-type-global.conf
new file mode 100644
index 0000000..e5704a3
--- /dev/null
+++ b/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/tests/policies/test-deps/modreq-type-opt.conf b/tests/policies/test-deps/modreq-type-opt.conf
new file mode 100644
index 0000000..65071d7
--- /dev/null
+++ b/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/tests/policies/test-deps/module.conf b/tests/policies/test-deps/module.conf
new file mode 100644
index 0000000..1971e4c
--- /dev/null
+++ b/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/tests/policies/test-deps/small-base.conf b/tests/policies/test-deps/small-base.conf
new file mode 100644
index 0000000..7c1cbe4
--- /dev/null
+++ b/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/tests/policies/test-expander/alias-base.conf b/tests/policies/test-expander/alias-base.conf
new file mode 100644
index 0000000..f3d0a6c
--- /dev/null
+++ b/tests/policies/test-expander/alias-base.conf
@@ -0,0 +1,498 @@
+# 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 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/tests/policies/test-expander/alias-module.conf b/tests/policies/test-expander/alias-module.conf
new file mode 100644
index 0000000..72d791e
--- /dev/null
+++ b/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/tests/policies/test-expander/base-base-only.conf b/tests/policies/test-expander/base-base-only.conf
new file mode 100644
index 0000000..80b87cc
--- /dev/null
+++ b/tests/policies/test-expander/base-base-only.conf
@@ -0,0 +1,43 @@
+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 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/tests/policies/test-expander/module.conf b/tests/policies/test-expander/module.conf
new file mode 100644
index 0000000..6186db7
--- /dev/null
+++ b/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/tests/policies/test-expander/role-base.conf b/tests/policies/test-expander/role-base.conf
new file mode 100644
index 0000000..219987c
--- /dev/null
+++ b/tests/policies/test-expander/role-base.conf
@@ -0,0 +1,479 @@
+# 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 types role_check_1_1_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+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/tests/policies/test-expander/role-module.conf b/tests/policies/test-expander/role-module.conf
new file mode 100644
index 0000000..1cc5d22
--- /dev/null
+++ b/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/tests/policies/test-expander/small-base.conf b/tests/policies/test-expander/small-base.conf
new file mode 100644
index 0000000..6f45a28
--- /dev/null
+++ b/tests/policies/test-expander/small-base.conf
@@ -0,0 +1,718 @@
+# 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 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 };
+}
+
+# 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/tests/policies/test-expander/user-base.conf b/tests/policies/test-expander/user-base.conf
new file mode 100644
index 0000000..660152e
--- /dev/null
+++ b/tests/policies/test-expander/user-base.conf
@@ -0,0 +1,482 @@
+# 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 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 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/tests/policies/test-expander/user-module.conf b/tests/policies/test-expander/user-module.conf
new file mode 100644
index 0000000..4ef3e62
--- /dev/null
+++ b/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/tests/policies/test-hooks/cmp_policy.conf b/tests/policies/test-hooks/cmp_policy.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/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/tests/policies/test-hooks/module_add_role_allow_trans.conf b/tests/policies/test-hooks/module_add_role_allow_trans.conf
new file mode 100644
index 0000000..c6ecd83
--- /dev/null
+++ b/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/tests/policies/test-hooks/module_add_symbols.conf b/tests/policies/test-hooks/module_add_symbols.conf
new file mode 100644
index 0000000..cf56e18
--- /dev/null
+++ b/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/tests/policies/test-hooks/small-base.conf b/tests/policies/test-hooks/small-base.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/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/tests/policies/test-linker/module1.conf b/tests/policies/test-linker/module1.conf
new file mode 100644
index 0000000..7cfb6cb
--- /dev/null
+++ b/tests/policies/test-linker/module1.conf
@@ -0,0 +1,138 @@
+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 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 types g_m1_type_2;
+
+#add type to base optional role test
+role o1_b_role_2 types g_m1_type_1;
+
+#optional base role w/ adds in 2 modules
+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 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 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 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/tests/policies/test-linker/module2.conf b/tests/policies/test-linker/module2.conf
new file mode 100644
index 0000000..3820cb7
--- /dev/null
+++ b/tests/policies/test-linker/module2.conf
@@ -0,0 +1,62 @@
+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 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 types g_m2_type_2;
+
+#optional base role w/ adds in 2 modules
+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 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/tests/policies/test-linker/small-base.conf b/tests/policies/test-linker/small-base.conf
new file mode 100644
index 0000000..2f166c9
--- /dev/null
+++ b/tests/policies/test-linker/small-base.conf
@@ -0,0 +1,593 @@
+# 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 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 types o1_b_type_1;
+
+	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 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 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/tests/test-common.c b/tests/test-common.c
new file mode 100644
index 0000000..058b743
--- /dev/null
+++ b/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/tests/test-common.h b/tests/test-common.h
new file mode 100644
index 0000000..5a1e650
--- /dev/null
+++ b/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/tests/test-cond.c b/tests/test-cond.c
new file mode 100644
index 0000000..32bf6f1
--- /dev/null
+++ b/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/tests/test-cond.h b/tests/test-cond.h
new file mode 100644
index 0000000..702d9e0
--- /dev/null
+++ b/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/tests/test-deps.c b/tests/test-deps.c
new file mode 100644
index 0000000..e7d2beb
--- /dev/null
+++ b/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/tests/test-deps.h b/tests/test-deps.h
new file mode 100644
index 0000000..fbd2ace
--- /dev/null
+++ b/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/tests/test-downgrade.c b/tests/test-downgrade.c
new file mode 100644
index 0000000..1ee7ff4
--- /dev/null
+++ b/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/tests/test-downgrade.h b/tests/test-downgrade.h
new file mode 100644
index 0000000..10a7c3b
--- /dev/null
+++ b/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/tests/test-expander-attr-map.c b/tests/test-expander-attr-map.c
new file mode 100644
index 0000000..5c24ced
--- /dev/null
+++ b/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/tests/test-expander-attr-map.h b/tests/test-expander-attr-map.h
new file mode 100644
index 0000000..6a10089
--- /dev/null
+++ b/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/tests/test-expander-roles.c b/tests/test-expander-roles.c
new file mode 100644
index 0000000..ecfa88e
--- /dev/null
+++ b/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/tests/test-expander-roles.h b/tests/test-expander-roles.h
new file mode 100644
index 0000000..380d2ef
--- /dev/null
+++ b/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/tests/test-expander-users.c b/tests/test-expander-users.c
new file mode 100644
index 0000000..549492b
--- /dev/null
+++ b/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/tests/test-expander-users.h b/tests/test-expander-users.h
new file mode 100644
index 0000000..cb12143
--- /dev/null
+++ b/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/tests/test-expander.c b/tests/test-expander.c
new file mode 100644
index 0000000..ded1d9d
--- /dev/null
+++ b/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/tests/test-expander.h b/tests/test-expander.h
new file mode 100644
index 0000000..5964133
--- /dev/null
+++ b/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/tests/test-linker-cond-map.c b/tests/test-linker-cond-map.c
new file mode 100644
index 0000000..0ef0d69
--- /dev/null
+++ b/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/tests/test-linker-cond-map.h b/tests/test-linker-cond-map.h
new file mode 100644
index 0000000..148c6f6
--- /dev/null
+++ b/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/tests/test-linker-roles.c b/tests/test-linker-roles.c
new file mode 100644
index 0000000..42f92d3
--- /dev/null
+++ b/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[2];
+	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/tests/test-linker-roles.h b/tests/test-linker-roles.h
new file mode 100644
index 0000000..f7407df
--- /dev/null
+++ b/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/tests/test-linker-types.c b/tests/test-linker-types.c
new file mode 100644
index 0000000..94f16ac
--- /dev/null
+++ b/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/tests/test-linker-types.h b/tests/test-linker-types.h
new file mode 100644
index 0000000..0c860eb
--- /dev/null
+++ b/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/tests/test-linker.c b/tests/test-linker.c
new file mode 100644
index 0000000..d08f219
--- /dev/null
+++ b/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/tests/test-linker.h b/tests/test-linker.h
new file mode 100644
index 0000000..16339a0
--- /dev/null
+++ b/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/utils/Makefile b/utils/Makefile
new file mode 100644
index 0000000..6864114
--- /dev/null
+++ b/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/utils/chkcon.c b/utils/chkcon.c
new file mode 100644
index 0000000..4c23d4c
--- /dev/null
+++ b/utils/chkcon.c
@@ -0,0 +1,42 @@
+#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 *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);
+}