Project import
diff --git a/libsepol/Android.mk b/libsepol/Android.mk
new file mode 100644
index 0000000..9507496
--- /dev/null
+++ b/libsepol/Android.mk
@@ -0,0 +1,137 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src_files := \
+ src/assertion.c \
+ src/avrule_block.c \
+ src/avtab.c \
+ src/boolean_record.c \
+ src/booleans.c \
+ src/conditional.c \
+ src/constraint.c \
+ src/context.c \
+ src/context_record.c \
+ src/debug.c \
+ src/ebitmap.c \
+ src/expand.c \
+ src/genbools.c \
+ src/genusers.c \
+ src/handle.c \
+ src/hashtab.c \
+ src/hierarchy.c \
+ src/iface_record.c \
+ src/interfaces.c \
+ src/link.c \
+ src/mls.c \
+ src/module.c \
+ src/module_to_cil.c \
+ src/node_record.c \
+ src/nodes.c \
+ src/polcaps.c \
+ src/policydb.c \
+ src/policydb_convert.c \
+ src/policydb_public.c \
+ src/port_record.c \
+ src/ports.c \
+ src/roles.c \
+ src/services.c \
+ src/sidtab.c \
+ src/symtab.c \
+ src/user_record.c \
+ src/users.c \
+ src/util.c \
+ src/write.c
+
+cil_src_files := \
+ cil/src/cil_binary.c \
+ cil/src/cil_build_ast.c \
+ cil/src/cil.c \
+ cil/src/cil_copy_ast.c \
+ cil/src/cil_find.c \
+ cil/src/cil_fqn.c \
+ cil/src/cil_lexer.l \
+ cil/src/cil_list.c \
+ cil/src/cil_log.c \
+ cil/src/cil_mem.c \
+ cil/src/cil_parser.c \
+ cil/src/cil_policy.c \
+ cil/src/cil_post.c \
+ cil/src/cil_reset_ast.c \
+ cil/src/cil_resolve_ast.c \
+ cil/src/cil_stack.c \
+ cil/src/cil_strpool.c \
+ cil/src/cil_symtab.c \
+ cil/src/cil_tree.c \
+ cil/src/cil_verify.c
+
+common_cflags := \
+ -D_GNU_SOURCE \
+ -Wall -W -Wundef \
+ -Wshadow -Wmissing-noreturn \
+ -Wmissing-format-attribute
+
+common_includes := \
+ $(LOCAL_PATH)/include/ \
+ $(LOCAL_PATH)/src/ \
+ $(LOCAL_PATH)/cil/include/ \
+ $(LOCAL_PATH)/cil/src/ \
+
+##
+# "-x c" forces the lex/yacc files to be compiled as c the build system
+# otherwise forces them to be c++. Need to also add an explicit -std because the
+# build system will soon default C++ to -std=c++11.
+yacc_flags := -x c -std=gnu89
+
+##
+# libsepol.so
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CPPFLAGS := $(yacc_flags)
+LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+##
+# libsepol.a
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CPPFLAGS := $(yacc_flags)
+LOCAL_SRC_FILES := $(common_src_files) $(cil_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+##
+# chkcon
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := chkcon
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := utils/chkcon.c
+LOCAL_SHARED_LIBRARIES := libsepol
+
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsepol
+LOCAL_MODULE_TAGES := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES := $(common_src_files)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libsepol/COPYING b/libsepol/COPYING
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/libsepol/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/libsepol/ChangeLog b/libsepol/ChangeLog
new file mode 100644
index 0000000..95e56d4
--- /dev/null
+++ b/libsepol/ChangeLog
@@ -0,0 +1,886 @@
+ * Fix neverallowxperm checking on attributes, from Jeff Vander Stoep.
+ * Remove libsepol.map when cleaning, from Nicolas Iooss.
+ * Add high-level language line marking support to CIL, from James Carter.
+ * Change logic of bounds checking to match change in kernel, from James Carter.
+ * Fix multiple spelling errors, from Laurent Bigonville.
+ * Only apply bounds checking to source types in rules, from Stephen Smalley.
+ * Fix CIL and not add an attribute as a type in the attr_type_map, from James Carter
+ * Build policy on systems not supporting DCCP protocol, from Richard Haines.
+ * Fix extended permissions neverallow checking, from Jeff Vander Stoep.
+ * Fix CIL neverallow and bounds checking, from James Carter
+ * Android.mk: Add -D_GNU_SOURCE to common_cflags, from Nick Kralevich.
+ * Add support for portcon dccp protocol, from Richard Haines
+ * Fix bug in CIL when resetting classes, from Steve Lawrence
+
+2.5 2016-02-23
+ * Fix unused variable annotations, from Nicolas Iooss.
+ * Fix uninitialized variable in CIL, from Nicolas Iooss.
+ * Validate extended avrules and permissionxs in CIL, from Steve Lawrence.
+ * Add support in CIL for neverallowx, from Steve Lawrence.
+ * Fully expand neverallowxperm rules, from Richard Haines.
+ * Add support for unordered classes to CIL, from Yuli Khodorkovskiy.
+ * Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep.
+ * Improve CIL block and macro call recursion detection, from Steve Lawrence
+ * Fix CIL uninitialized false positive in cil_binary, from Yuli Khodorkovskiy
+ * Provide error in CIL if classperms are empty, from Yuli Khodorkovskiy
+ * Add userattribute{set} functionality to CIL, from Yuli Khodorkovskiy
+ * fix CIL blockinherit copying segfault and add macro restrictions, from Steve Lawrence
+ * fix CIL NULL pointer dereference when copying classpermission/set, from Steve Lawrence
+ * Add CIL support for ioctl whitelists, from Steve Lawrence
+ * Fix memory leak when destroying avtab, from Steve Lawrence
+ * Replace sscanf in module_to_cil, from Yuli Khodorkovskiy.
+ * Improve CIL resolution error messages, from Steve Lawrence
+ * Fix policydb_read for policy versions < 24, from Stephen Smalley.
+ * Added CIL bounds checking and refactored CIL Neverallow checking, from James Carter
+ * Refactored libsepol Neverallow and bounds (hierarchy) checking, from James Carter
+ * Treat types like an attribute in the attr_type_map, from James Carter
+ * Add new ebitmap function named ebitmap_match_any(), from James Carter
+ * switch operations to extended perms, from Jeff Vander Stoep.
+ * Write auditadm_r and secadm_r roles to base module when writing CIL, from Steve Lawrence
+ * Fix module to CIL to only associate declared roleattributes with in-scope types, from Steve Lawrence
+ * Don't allow categories/sensitivities inside blocks in CIL, from Yuli Khodorkovskiy.
+ * Replace fmemopen() with internal function in libsepol, from James Carter.
+ * Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy.
+ * Binary modules do not support ioctl rules, from Stephen Smalley.
+ * Add support for ioctl command whitelisting, from Jeff Vander Stoep.
+ * Don't use symbol versioning for static object files, from Yuli Khodorkovskiy.
+ * Add sepol_module_policydb_to_cil(), sepol_module_package_to_cil(), and sepol_ppfile_to_module_package(), from James Carter.
+ * Move secilc out of libsepol, from Yuli Khodorkovskiy.
+ * fix building Xen policy with devicetreecon, and add devicetreecon
+ CIL documentation, from Richard Haines.
+ * bool_copy_callback set state on creation, from Thomas Hurd.
+ * Add device tree ocontext nodes to Xen policy, from Daniel De Graaf.
+ * Widen Xen IOMEM context entries, from Daniel De Graaf.
+ * Update CIL documentation, from Richard Haines
+ * Fix error path in mls_semantic_level_expand(), from Chris PeBenito.
+ * Fix MacOS X build, from Stephen Smalley.
+ * Enabling building CIL in Android, from Stephen Smalley.
+ * Update to latest CIL, includes new name resolution and fixes ordering
+ issues with blockinherit statements, and bug fixes
+
+2.4 2015-02-02
+ * Remove assumption that SHLIBDIR is ../../ relative to LIBDIR, from Steve
+ Lawrence
+ * Fix bugs found by hardened gcc flags, from Nicolas Iooss.
+ * Build CIL into libsepol. libsepol can be built without CIL by setting the
+ DISABLE_CIL flag to 'y', from Steve Lawrence
+ * Add an API function to set target_platform, from Steve Lawrence
+ * Report all neverallow violations, from Stephen Smalley
+ * Improve check_assertions performance through hash tweaks from John Brooks.
+ * Allow libsepol C++ static library on device from Daniel Cashman.
+
+2.3 2014-05-06
+ * Improve error message for name-based transition conflicts.
+ * Revert libsepol: filename_trans: use some better sorting to compare and merge.
+ * Report source file and line information for neverallow failures.
+ * Fix valgrind errors in constraint_expr_eval_reason from Richard Haines.
+ * Add sepol_validate_transition_reason_buffer function from Richard Haines.
+
+2.2 2013-10-30
+ * Allow constraint denial cause to be determined from Richard Haines.
+ - Add kernel policy version 29.
+ - Add modular policy version 17.
+ - Add sepol_compute_av_reason_buffer(), sepol_string_to_security_class(), sepol_string_to_av_perm().
+ * Support overriding Makefile RANLIB from Sven Vermeulen.
+ * Fix man pages from Laurent Bigonville.
+
+2.1.9 2013-02-01
+ * filename_trans: use some better sorting to compare and merge
+ * coverity fixes
+ * implement default type policy syntax
+ * Fix memory leak issues found by Klocwork
+
+2.1.8 2012-09-13
+ * fix neverallow checking on attributes
+ * Move context_copy() after switch block in ocontext_copy_*().
+ * check for missing initial SID labeling statement.
+ * Add always_check_network policy capability
+ * role_fix_callback skips out-of-scope roles during expansion.
+
+2.1.7 2012-06-28
+ * reserve policycapability for redhat testing of ptrace child
+ * cosmetic changes to make the source easier to read
+ * prepend instead of append to filename_trans list
+ * Android/MacOS X build support
+
+2.1.6 2012-04-23
+ * allocate enough space to hold filename in trans rules
+
+2.1.5 2012-03-28
+ * checkpolicy: implement new default labeling behaviors
+
+2.1.4 2011-10-03
+ * regenerate .pc on VERSION change
+ * Move ebitmap_* functions from mcstrans to libsepol
+ * expand: do filename_trans type comparison on mapped representation
+
+2.1.3 2011-09-15
+ * Skip writing role attributes for policy.X and
+ * Indicate when boolean is indeed a tunable.
+ * Separate tunable from boolean during compile.
+ * Write and read TUNABLE flags in related
+ * Copy and check the cond_bool_datum_t.flags during link.
+ * Permanently discard disabled branches of tunables in
+ * Skip tunable identifier and cond_node_t in expansion.
+ * Create a new preserve_tunables flag
+ * Preserve tunables when required by semodule program.
+ * setools expects expand_module_avrules to be an exported
+ * tree: default make target to all not
+
+2.1.2 2011-08-03
+ * Only call role_fix_callback for base.p_roles during expansion.
+ * use mapped role number instead of module role number
+
+2.1.1 2011-08-01
+ * Minor fix to reading policy with filename transition rules
+
+2.1.0 2011-07-27
+ * Release, minor version bump
+
+2.0.46 2011-07-25
+ * Add role attribute support by Harry Ciao
+
+2.0.45 2011-05-02
+ * Warn if filename_trans rules are dropped by Steve Lawrence.
+
+2.0.44 2011-04-13
+ * Fixes for new role_transition class field by Eric Paris.
+ * Add libsepol support for filename_trans rules by Eric Paris.
+
+2.0.43 2011-04-11
+ * Add new class field in role_transition by Harry Ciao.
+
+2.0.42 2010-12-16
+ * Fix compliation under GCC 4.6 by Justin Mattock
+
+2.0.41 2009-11-18
+ * Fixed typo in error message from Manoj Srivastava.
+
+2.0.40 2009-10-29
+ * Add pkgconfig file from Eamon Walsh.
+
+2.0.39 2009-10-14
+ * Add support for building Xen policies from Paul Nuzzi.
+
+2.0.38 2009-09-01
+ * Check last offset in the module package against the file size.
+ Reported by Manoj Srivastava for bug filed by Max Kellermann.
+
+2.0.37 2009-07-07
+ * Add method to check disable dontaudit flag from Christopher Pardy.
+
+2.0.36 2009-03-25
+ * Fix boolean state smashing from Joshua Brindle.
+
+2.0.35 2009-02-19
+ * Fix alias field in module format, caused by boundary format change
+ from Caleb Case.
+
+2.0.34 2008-10-09
+ * Add bounds support from KaiGai Kohei.
+ * Fix invalid aliases bug from Joshua Brindle.
+
+2.0.33 2008-09-29
+ * Revert patch that removed expand_rule.
+
+2.0.32 2008-07-07
+ * Allow require then declare in the source policy from Joshua Brindle.
+
+2.0.31 2008-06-13
+ * Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley.
+
+2.0.30 2008-06-06
+ * Fix endianness bug in the handling of network node addresses from Stephen Smalley.
+ Only affects big endian platforms.
+ Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc.
+
+2.0.29 2008-05-27
+ * Merge user and role mapping support from Joshua Brindle.
+
+2.0.28 2008-05-05
+ * Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley.
+
+2.0.27 2008-04-18
+ * Belatedly merge test for policy downgrade from Todd Miller.
+
+2.0.26 2008-03-24
+ * Add permissive domain support from Eric Paris.
+
+2.0.25 2008-03-04
+ * Drop unused ->buffer field from struct policy_file.
+
+2.0.24 2008-03-04
+ * Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller.
+
+2.0.23 2008-02-28
+ * Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley.
+
+2.0.22 2008-02-28
+ * Add support for open_perms policy capability from Eric Paris.
+
+2.0.21 2008-02-20
+ * Fix invalid memory allocation in policydb_index_others() from Jason Tang.
+
+2.0.20 2008-02-04
+ * Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley.
+
+2.0.19 2008-02-02
+ * Add support for consuming avrule_blocks during expansion to reduce
+ peak memory usage from Joshua Brindle.
+
+2.0.18 2008-01-02
+ * Added support for policy capabilities from Todd Miller.
+
+2.0.17 2007-12-21
+ * Prevent generation of policy.18 with MLS enabled from Todd Miller.
+
+2.0.16 2007-12-07
+ * print module magic number in hex on mismatch, from Todd Miller.
+
+2.0.15 2007-11-29
+ * clarify and reduce neverallow error reporting from Stephen Smalley.
+
+2.0.14 2007-11-05
+ * Reject self aliasing at link time from Stephen Smalley.
+
+2.0.13 2007-11-05
+ * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley.
+
+2.0.12 2007-10-11
+ * Fixed bug in require checking from Stephen Smalley.
+ * Added user hierarchy checking from Todd Miller.
+
+2.0.11 2007-09-24
+ * Pass CFLAGS to CC even on link command, per Dennis Gilmore.
+
+2.0.10 2007-09-18
+ * Merged support for the handle_unknown policydb flag from Eric Paris.
+
+2.0.9 2007-08-29
+ * Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper.
+
+2.0.8 2007-08-28
+ * Fixed module_package_read_offsets bug introduced by the prior patch.
+
+2.0.7 2007-08-23
+ * Eliminate unaligned accesses from policy reading code from Stephen Smalley.
+
+2.0.6 2007-08-16
+ * Allow dontaudits to be turned off during policy expansion from
+ Joshua Brindle.
+
+2.0.5 2007-08-01
+ * Fix sepol_context_clone to handle a NULL context correctly.
+ This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL)
+ to set the file context entry to "<<none>>".
+
+2.0.4 2007-06-20
+ * Merged error handling patch from Eamon Walsh.
+
+2.0.3 2007-04-13
+ * Merged add boolmap argument to expand_module_avrules() from Chris PeBenito.
+
+2.0.2 2007-03-30
+ * Merged fix from Karl to remap booleans at expand time to
+ avoid holes in the symbol table.
+
+2.0.1 2007-02-06
+ * Merged libsepol segfault fix from Stephen Smalley for when
+ sensitivities are required but not present in the base.
+
+2.0.0 2007-02-01
+ * Merged patch to add errcodes.h to libsepol by Karl MacMillan.
+
+1.16.0 2007-01-18
+ * Updated version for stable branch.
+
+1.15.3 2006-11-27
+ * Merged patch to compile wit -fPIC instead of -fpic from
+ Manoj Srivastava to prevent hitting the global offest table
+ limit. Patch changed to include libselinux and libsemanage in
+ addition to libselinux.
+1.15.2 2006-10-31
+ * Merged fix from Karl MacMillan for a segfault when linking
+ non-MLS modules with users in them.
+
+1.15.1 2006-10-24
+ * Merged fix for version comparison that was preventing range
+ transition rules from being written for a version 5 base policy
+ from Darrel Goeddel.
+
+1.14 2006-10-17
+ * Updated version for release.
+
+1.12.28 2006-09-28
+ * Build libsepol's static object files with -fpic
+
+1.12.27 2006-09-28
+ * Merged mls user and range_transition support in modules
+ from Darrel Goeddel
+
+1.12.26 2006-09-05
+ * Merged range transition enhancements and user format changes
+ Darrel Goeddel
+
+1.12.25 2006-08-24
+ * Merged conditionally expand neverallows patch from Jeremy Mowery.
+ * Merged refactor expander patch from Jeremy Mowery.
+
+1.12.24 2006-08-03
+ * Merged libsepol unit tests from Joshua Brindle.
+
+1.12.23 2006-08-03
+ * Merged symtab datum patch from Karl MacMillan.
+
+1.12.22 2006-08-03
+ * Merged netfilter contexts support from Chris PeBenito.
+
+1.12.21 2006-07-28
+ * Merged helpful hierarchy check errors patch from Joshua Brindle.
+
+1.12.20 2006-07-25
+ * Merged semodule_deps patch from Karl MacMillan.
+ This adds source module names to the avrule decls.
+
+1.12.19 2006-06-29
+ * Lindent.
+
+1.12.18 2006-06-26
+ * Merged optionals in base take 2 patch set from Joshua Brindle.
+
+1.12.17 2006-05-30
+ * Revert 1.12.16.
+
+1.12.16 2006-05-30
+ * Merged cleaner fix for bool_ids overflow from Karl MacMillan,
+ replacing the prior patch.
+
+1.12.15 2006-05-30
+ * Merged fixes for several memory leaks in the error paths during
+ policy read from Serge Hallyn.
+
+1.12.14 2006-05-25
+ * Fixed bool_ids overflow bug in cond_node_find and cond_copy_list,
+ based on bug report and suggested fix by Cedric Roux.
+
+1.12.13 2006-05-24
+ * Merged sens_copy_callback, check_role_hierarchy_callback,
+ and node_from_record fixes from Serge Hallyn.
+
+1.12.12 2006-05-22
+ * Added sepol_policydb_compat_net() interface for testing whether
+ a policy requires the compatibility support for network checks
+ to be enabled in the kernel.
+
+1.12.11 2006-05-17
+ * Merged patch to initialize sym_val_to_name arrays from Kevin Carr.
+ Reworked to use calloc in the first place, and converted some other
+ malloc/memset pairs to calloc calls.
+
+1.12.10 2006-05-08
+ * Merged patch to revert role/user decl upgrade from Karl MacMillan.
+
+1.12.9 2006-05-08
+ * Dropped tests from all Makefile target.
+
+1.12.8 2006-05-05
+ * Merged fix warnings patch from Karl MacMillan.
+
+1.12.7 2006-05-05
+ * Merged libsepol test framework patch from Karl MacMillan.
+
+1.12.6 2006-04-28
+ * Fixed cond_normalize to traverse the entire cond list at link time.
+
+1.12.5 2006-04-03
+ * Merged fix for leak of optional package sections from Ivan Gyurdiev.
+
+1.12.4 2006-03-29
+ * Generalize test for bitmap overflow in ebitmap_set_bit.
+
+1.12.3 2006-03-27
+ * Fixed attr_convert_callback and expand_convert_type_set
+ typemap bug.
+
+1.12.2 2006-03-24
+ * Fixed avrule_block_write num_decls endian bug.
+
+1.12.1 2006-03-20
+ * Fixed sepol_module_package_write buffer overflow bug.
+
+1.12 2006-03-14
+ * Updated version for release.
+
+1.11.20 2006-03-08
+ * Merged cond_evaluate_expr fix from Serge Hallyn (IBM).
+ * Fixed bug in copy_avrule_list reported by Ivan Gyurdiev.
+
+1.11.19 2006-02-21
+ * Merged sepol_policydb_mls_enabled interface and error handling
+ changes from Ivan Gyurdiev.
+
+1.11.18 2006-02-16
+ * Merged node_expand_addr bugfix and node_compare* change from
+ Ivan Gyurdiev.
+
+1.11.17 2006-02-15
+ * Merged nodes, ports: always prepend patch from Ivan Gyurdiev.
+ * Merged bug fix patch from Ivan Gyurdiev.
+
+1.11.16 2006-02-14
+ * Added a defined flag to level_datum_t for use by checkpolicy.
+
+1.11.15 2006-02-14
+ * Merged nodecon support patch from Ivan Gyurdiev.
+ * Merged cleanups patch from Ivan Gyurdiev.
+
+1.11.14 2006-02-13
+ * Merged optionals in base patch from Joshua Brindle.
+
+1.11.13 2006-02-07
+ * Merged seuser/user_extra support patch from Joshua Brindle.
+ * Merged fix patch from Ivan Gyurdiev.
+
+1.11.12 2006-02-02
+ * Merged clone record on set_con patch from Ivan Gyurdiev.
+
+1.11.11 2006-02-01
+ * Merged assertion copying bugfix from Joshua Brindle.
+ * Merged sepol_av_to_string patch from Joshua Brindle.
+
+1.11.10 2006-01-30
+ * Merged cond_expr mapping and package section count bug fixes
+ from Joshua Brindle.
+ * Merged improve port/fcontext API patch from Ivan Gyurdiev.
+ * Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev.
+
+1.11.9 2006-01-12
+ * Merged size_t -> unsigned int patch from Ivan Gyurdiev.
+
+1.11.8 2006-01-09
+ * Merged 2nd const in APIs patch from Ivan Gyurdiev.
+
+1.11.7 2006-01-06
+ * Merged const in APIs patch from Ivan Gyurdiev.
+ * Merged compare2 function patch from Ivan Gyurdiev.
+
+1.11.6 2006-01-06
+ * Fixed hierarchy checker to only check allow rules.
+
+1.11.5 2006-01-05
+ * Merged further fixes from Russell Coker, specifically:
+ - av_to_string overflow checking
+ - sepol_context_to_string error handling
+ - hierarchy checking memory leak fixes and optimizations
+ - avrule_block_read variable initialization
+ * Marked deprecated code in genbools and genusers.
+
+1.11.4 2006-01-05
+ * Merged bugfix for sepol_port_modify from Russell Coker.
+
+1.11.3 2006-01-05
+ * Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev.
+ * Merged port ordering patch from Ivan Gyurdiev.
+
+1.11.2 2006-01-04
+ * Merged patch series from Ivan Gyurdiev.
+ This includes patches to:
+ - support ordering of records in compare function
+ - enable port interfaces
+ - add interfaces for context validity and range checks
+ - add include guards
+
+1.11.1 2005-12-16
+ * Fixed mls_range_cpy bug.
+
+1.10 2005-12-07
+ * Updated version for release.
+
+1.9.42 2005-12-05
+ * Dropped handle from user_del_role interface.
+
+1.9.41 2005-11-28
+ * Merged remove defrole from sepol patch from Ivan Gyurdiev.
+
+1.9.40 2005-11-15
+ * Merged module function and map file cleanup from Ivan Gyurdiev.
+ * Merged MLS and genusers cleanups from Ivan Gyurdiev.
+
+1.9.39 2005-11-09
+ Prepare for removal of booleans* and *.users files.
+ * Cleaned up sepol_genbools to not regenerate the image if
+ there were no changes in the boolean values, including the
+ degenerate case where there are no booleans or booleans.local
+ files.
+ * Cleaned up sepol_genusers to not warn on missing local.users.
+
+1.9.38 2005-11-08
+ * Removed sepol_port_* from libsepol.map, as the port interfaces
+ are not yet stable.
+
+1.9.37 2005-11-04
+ * Merged context destroy cleanup patch from Ivan Gyurdiev.
+
+1.9.36 2005-11-03
+ * Merged context_to_string interface change patch from Ivan Gyurdiev.
+
+1.9.35 2005-11-01
+ * Added src/dso.h and src/*_internal.h.
+ Added hidden_def for exported symbols used within libsepol.
+ Added hidden for symbols that should not be exported by
+ the wildcards in libsepol.map.
+
+1.9.34 2005-10-31
+ * Merged record interface, record bugfix, and set_roles patches
+ from Ivan Gyurdiev.
+
+1.9.33 2005-10-27
+ * Merged count specification change from Ivan Gyurdiev.
+
+1.9.32 2005-10-26
+ * Added further checking and error reporting to
+ sepol_module_package_read and _info.
+
+1.9.31 2005-10-26
+ * Merged sepol handle passing, DEBUG conversion, and memory leak
+ fix patches from Ivan Gyurdiev.
+
+1.9.30 2005-10-25
+ * Removed processing of system.users from sepol_genusers and
+ dropped delusers logic.
+
+1.9.29 2005-10-25
+ * Removed policydb_destroy from error path of policydb_read,
+ since create/init/destroy/free of policydb is handled by the
+ caller now.
+ * Fixed sepol_module_package_read to handle a failed policydb_read
+ properly.
+
+1.9.28 2005-10-25
+ * Merged query/exists and count patches from Ivan Gyurdiev.
+
+1.9.27 2005-10-25
+ * Merged fix for pruned types in expand code from Joshua Brindle.
+ * Merged new module package format code from Joshua Brindle.
+
+1.9.26 2005-10-24
+ * Merged context interface cleanup, record conversion code,
+ key passing, and bug fix patches from Ivan Gyurdiev.
+
+1.9.25 2005-10-21
+ * Merged users cleanup patch from Ivan Gyurdiev.
+
+1.9.24 2005-10-21
+ * Merged user record memory leak fix from Ivan Gyurdiev.
+ * Merged reorganize users patch from Ivan Gyurdiev.
+
+1.9.23 2005-10-19
+ * Added check flag to expand_module() to control assertion
+ and hierarchy checking on expansion.
+
+1.9.22 2005-10-19
+ * Reworked check_assertions() and hierarchy_check_constraints()
+ to take handles and use callback-based error reporting.
+ * Changed expand_module() to call check_assertions() and
+ hierarchy_check_constraints() prior to returning the expanded
+ policy.
+
+1.9.21 2005-10-18
+ * Changed sepol_module_package_set_file_contexts to copy the
+ file contexts data since it is internally managed.
+
+1.9.20 2005-10-18
+ * Added sepol_policy_file_set_handle interface to associate
+ a handle with a policy file.
+ * Added handle argument to policydb_from_image/to_image.
+ * Added sepol_module_package_set_file_contexts interface.
+ * Dropped sepol_module_package_create_file interface.
+ * Reworked policydb_read/write, policydb_from_image/to_image,
+ and sepol_module_package_read/write to use callback-based error
+ reporting system rather than DEBUG.
+
+1.9.19 2005-10-17
+ * Reworked link_packages, link_modules, and expand_module to use
+ callback-based error reporting system rather than error buffering.
+
+1.9.18 2005-10-14
+ * Merged conditional expression mapping fix in the module linking
+ code from Joshua Brindle.
+
+1.9.17 2005-10-13
+ * Hid sepol_module_package type definition, and added get interfaces.
+
+1.9.16 2005-10-13
+ * Merged new callback-based error reporting system from Ivan
+ Gyurdiev.
+
+1.9.15 2005-10-13
+ * Merged support for require blocks inside conditionals from
+ Joshua Brindle (Tresys).
+
+1.9.14 2005-10-07
+ * Fixed use of policydb_from_image/to_image to ensure proper
+ init of policydb.
+
+1.9.13 2005-10-07
+ * Isolated policydb internal headers under <sepol/policydb/*.h>.
+ These headers should only be used by users of the static libsepol.
+ Created new <sepol/policydb.h> with new public types and interfaces
+ for shared libsepol.
+ Created new <sepol/module.h> with public types and interfaces moved
+ or wrapped from old module.h, link.h, and expand.h, adjusted for
+ new public types for policydb and policy_file.
+ Added public interfaces to libsepol.map.
+ Some implementation changes visible to users of the static libsepol:
+ 1) policydb_read no longer calls policydb_init.
+ Caller must do so first.
+ 2) policydb_init no longer takes policy_type argument.
+ Caller must set policy_type separately.
+ 3) expand_module automatically enables the global branch.
+ Caller no longer needs to do so.
+ 4) policydb_write uses the policy_type and policyvers from the
+ policydb itself, and sepol_set_policyvers() has been removed.
+
+1.9.12 2005-10-06
+ * Merged function renaming and static cleanup from Ivan Gyurdiev.
+
+1.9.11 2005-10-05
+ * Merged bug fix for check_assertions handling of no assertions
+ from Joshua Brindle (Tresys).
+
+1.9.10 2005-10-04
+ * Merged iterate patch from Ivan Gyurdiev.
+
+1.9.9 2005-10-03
+ * Merged MLS in modules patch from Joshua Brindle (Tresys).
+
+1.9.8 2005-09-30
+ * Merged pointer typedef elimination patch from Ivan Gyurdiev.
+ * Merged user list function, new mls functions, and bugfix patch
+ from Ivan Gyurdiev.
+
+1.9.7 2005-09-28
+ * Merged sepol_get_num_roles fix from Karl MacMillan (Tresys).
+
+1.9.6 2005-09-23
+ * Merged bug fix patches from Joshua Brindle (Tresys).
+
+1.9.5 2005-09-21
+ * Merged boolean record and memory leak fix patches from Ivan
+ Gyurdiev.
+
+1.9.4 2005-09-19
+ * Merged interface record patch from Ivan Gyurdiev.
+
+1.9.3 2005-09-14
+ * Merged fix for sepol_enable/disable_debug from Ivan
+ Gyurdiev.
+
+1.9.2 2005-09-14
+ * Merged stddef.h patch and debug conversion patch from
+ Ivan Gyurdiev.
+
+1.9.1 2005-09-09
+ * Fixed expand_avtab and expand_cond_av_list to keep separate
+ entries with identical keys but different enabled flags.
+
+1.8 2005-09-06
+ * Updated version for release.
+
+1.7.24 2005-08-31
+ * Fixed symtab_insert return value for duplicate declarations.
+
+1.7.23 2005-08-31
+ * Merged fix for memory error in policy_module_destroy from
+ Jason Tang (Tresys).
+
+1.7.22 2005-08-26
+ * Merged fix for memory leak in sepol_context_to_sid from
+ Jason Tang (Tresys).
+
+1.7.21 2005-08-25
+ * Merged fixes for resource leaks on error paths and
+ change to scope_destroy from Joshua Brindle (Tresys).
+
+1.7.20 2005-08-23
+ * Merged more fixes for resource leaks on error paths
+ from Serge Hallyn (IBM). Bugs found by Coverity.
+
+1.7.19 2005-08-19
+ * Changed to treat all type conflicts as fatal errors.
+
+1.7.18 2005-08-18
+ * Merged several error handling fixes from
+ Serge Hallyn (IBM). Bugs found by Coverity.
+
+1.7.17 2005-08-15
+ * Fixed further memory leaks found by valgrind.
+
+1.7.16 2005-08-15
+ * Fixed several memory leaks found by valgrind.
+
+1.7.15 2005-08-12
+ * Fixed empty list test in cond_write_av_list. Bug found by
+ Coverity, reported by Serge Hallyn (IBM).
+ * Merged patch to policydb_write to check errors
+ when writing the type->attribute reverse map from
+ Serge Hallyn (IBM). Bug found by Coverity.
+ * Fixed policydb_destroy to properly handle NULL type_attr_map
+ or attr_type_map.
+
+1.7.14 2005-08-12
+ * Fixed use of uninitialized data by expand_avtab_node by
+ clearing type_val_to_struct in policydb_index_others.
+
+1.7.13 2005-08-11
+ * Improved memory use by SELinux by both reducing the avtab
+ node size and reducing the number of avtab nodes (by not
+ expanding attributes in TE rules when possible). Added
+ expand_avtab and expand_cond_av_list functions for use by
+ assertion checker, hierarchy checker, compatibility code,
+ and dispol. Added new inline ebitmap operators and converted
+ existing users of ebitmaps to the new operators for greater
+ efficiency.
+ Note: The binary policy format version has been incremented to
+ version 20 as a result of these changes.
+
+1.7.12 2005-08-10
+ * Fixed bug in constraint_node_clone handling of name sets.
+
+1.7.11 2005-08-08
+ * Fix range_trans_clone to map the type values properly.
+
+1.7.10 2005-08-02
+ * Merged patch to move module read/write code from libsemanage
+ to libsepol from Jason Tang (Tresys).
+
+1.7.9 2005-08-02
+ * Enabled further compiler warning flags and fixed them.
+
+1.7.8 2005-08-02
+ * Merged user, context, port records patch from Ivan Gyurdiev.
+ * Merged key extract function patch from Ivan Gyurdiev.
+
+1.7.7 2005-07-27
+ * Merged mls_context_to_sid bugfix from Ivan Gyurdiev.
+
+1.7.6 2005-07-26
+ * Merged context reorganization, memory leak fixes,
+ port and interface loading, replacements for genusers and
+ genbools, debug traceback, and bugfix patches from Ivan Gyurdiev.
+ * Merged uninitialized variable bugfix from Dan Walsh.
+
+1.7.5 2005-07-18
+ * Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat).
+ * Removed genpolbools and genpolusers utilities.
+
+1.7.4 2005-07-18
+ * Merged hierarchy check fix from Joshua Brindle (Tresys).
+
+1.7.3 2005-07-13
+ * Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat).
+
+1.7.2 2005-07-11
+ * Merged genbools debugging message cleanup from Red Hat.
+
+1.7.1 2005-07-06
+ * Merged loadable module support from Tresys Technology.
+
+1.6 2005-06-20
+ * Updated version for release.
+
+1.5.10 2005-05-19
+ * License changed to LGPL v2.1, see COPYING.
+
+1.5.9 2005-05-16
+ * Added sepol_genbools_policydb and sepol_genusers_policydb for
+ audit2why.
+
+1.5.8 2005-05-13
+ * Added sepol_ prefix to Flask types to avoid
+ namespace collision with libselinux.
+
+1.5.7 2005-05-13
+ * Added sepol_compute_av_reason() for audit2why.
+
+1.5.6 2005-04-25
+ * Fixed bug in role hierarchy checker.
+
+1.5.5 2005-04-13
+ * Merged hierarchical type/role patch from Tresys Technology.
+ * Merged MLS fixes from Darrel Goeddel of TCS.
+
+1.5.4 2005-04-13
+ * Changed sepol_genusers to not delete users by default,
+ and added a sepol_set_delusers function to enable deletion.
+ Also, removed special case handling of system_u and user_u.
+
+1.5.3 2005-03-29
+ * Merged booleans.local patch from Dan Walsh.
+
+1.5.2 2005-03-16
+ * Added man page for sepol_check_context.
+
+1.5.1 2005-03-15
+ * Added man page for sepol_genusers function.
+ * Merged man pages for genpolusers and chkcon from Manoj Srivastava.
+
+1.4 2005-03-09
+ * Updated version for release.
+
+1.3.8 2005-03-08
+ * Cleaned up error handling in sepol_genusers and sepol_genbools.
+
+1.3.7 2005-02-28
+ * Merged sepol_debug and fclose patch from Dan Walsh.
+
+1.3.6 2005-02-22
+ * Changed sepol_genusers to also use getline and correctly handle
+ EOL.
+
+1.3.5 2005-02-17
+ * Merged range_transition support from Darrel Goeddel (TCS).
+
+1.3.4 2005-02-16
+ * Added sepol_genusers function.
+
+1.3.3 2005-02-14
+ * Merged endianness and compute_av patches from Darrel Goeddel (TCS).
+
+1.3.2 2005-02-09
+ * Changed relabel Makefile target to use restorecon.
+
+1.3.1 2005-01-26
+ * Merged enhanced MLS support from Darrel Goeddel (TCS).
+
+1.2.1 2005-01-19
+ * Merged build fix patch from Manoj Srivastava.
+
+1.2 2004-10-07
+ * MLS build fixes.
+ * Added sepol_set_policydb_from_file and sepol_check_context for setfiles.
+
+1.0 2004-08-19
+ * Initial public release.
+
+0.4 2004-08-13
+ * Merged patch from Dan Walsh to ignore case on booleans.
+ * Changed sepol_genbools* to preserve the original policy version.
+ * Replaced exported global variables with set functions.
+ * Moved genpolbools utility from checkpolicy to libsepol.
+ * Added man pages for sepol_genbools* and genpolbools.
+
+0.3 2004-08-10
+ * Added ChangeLog, COPYING, spec file.
+ * Added sepol_genbools_array() for load_policy.
+ * Created libsepol.map to limit exported symbols in shared library.
+
+0.2 2004-08-09
+ * Exported other functions for checkpolicy and friends.
+ * Renamed service and sidtab functions to avoid libselinux conflict.
+ * Removed original code from checkpolicy, which now uses libsepol.
+ * Code cleanup: kill legacy references to kernel types/functions.
+
+0.1 2004-08-06
+ * Moved checkpolicy core logic into a library.
+ * Exported sepol_genbools() for load_policy.
diff --git a/libsepol/Makefile b/libsepol/Makefile
new file mode 100644
index 0000000..5b5d03e
--- /dev/null
+++ b/libsepol/Makefile
@@ -0,0 +1,30 @@
+DISABLE_CIL ?= n
+
+export DISABLE_CIL
+
+all:
+ $(MAKE) -C src
+ $(MAKE) -C utils
+
+install:
+ $(MAKE) -C include install
+ $(MAKE) -C src install
+ $(MAKE) -C utils install
+ $(MAKE) -C man install
+
+relabel:
+ $(MAKE) -C src relabel
+
+clean:
+ $(MAKE) -C src clean
+ $(MAKE) -C utils clean
+ $(MAKE) -C tests clean
+
+indent:
+ $(MAKE) -C src $@
+ $(MAKE) -C include $@
+ $(MAKE) -C utils $@
+
+test:
+ $(MAKE) -C tests test
+
diff --git a/libsepol/VERSION b/libsepol/VERSION
new file mode 100644
index 0000000..95e3ba8
--- /dev/null
+++ b/libsepol/VERSION
@@ -0,0 +1 @@
+2.5
diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h
new file mode 100644
index 0000000..e4b10c5
--- /dev/null
+++ b/libsepol/cil/include/cil/cil.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_H_
+#define CIL_H_
+
+#include <sepol/policydb/policydb.h>
+
+struct cil_db;
+typedef struct cil_db cil_db_t;
+
+extern void cil_db_init(cil_db_t **db);
+extern void cil_db_destroy(cil_db_t **db);
+
+extern int cil_add_file(cil_db_t *db, char *name, char *data, size_t size);
+
+extern int cil_compile(cil_db_t *db);
+extern int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db);
+extern int cil_userprefixes_to_string(cil_db_t *db, char **out, size_t *size);
+extern int cil_selinuxusers_to_string(cil_db_t *db, char **out, size_t *size);
+extern int cil_filecons_to_string(cil_db_t *db, char **out, size_t *size);
+extern void cil_set_disable_dontaudit(cil_db_t *db, int disable_dontaudit);
+extern void cil_set_disable_neverallow(cil_db_t *db, int disable_neverallow);
+extern void cil_set_preserve_tunables(cil_db_t *db, int preserve_tunables);
+extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown);
+extern void cil_set_mls(cil_db_t *db, int mls);
+extern void cil_set_target_platform(cil_db_t *db, int target_platform);
+extern void cil_set_policy_version(cil_db_t *db, int policy_version);
+
+enum cil_log_level {
+ CIL_ERR = 1,
+ CIL_WARN,
+ CIL_INFO
+};
+extern void cil_set_log_level(enum cil_log_level lvl);
+extern void cil_set_log_handler(void (*handler)(int lvl, char *msg));
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 2, 3)))
+#endif
+extern void cil_log(enum cil_log_level lvl, const char *msg, ...);
+
+extern void cil_set_malloc_error_handler(void (*handler)(void));
+
+#endif
diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
new file mode 100644
index 0000000..929ab19
--- /dev/null
+++ b/libsepol/cil/src/cil.c
@@ -0,0 +1,2570 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/symtab.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+#include "cil_build_ast.h"
+
+#include "cil_parser.h"
+#include "cil_build_ast.h"
+#include "cil_resolve_ast.h"
+#include "cil_fqn.h"
+#include "cil_post.h"
+#include "cil_binary.h"
+#include "cil_policy.h"
+#include "cil_strpool.h"
+#include "dso.h"
+
+#ifndef DISABLE_SYMVER
+asm(".symver cil_build_policydb_pdb, cil_build_policydb@");
+asm(".symver cil_build_policydb_create_pdb, cil_build_policydb@@LIBSEPOL_1.1");
+
+asm(".symver cil_compile_pdb, cil_compile@");
+asm(".symver cil_compile_nopdb, cil_compile@@LIBSEPOL_1.1");
+
+asm(".symver cil_userprefixes_to_string_pdb, cil_userprefixes_to_string@");
+asm(".symver cil_userprefixes_to_string_nopdb, cil_userprefixes_to_string@@LIBSEPOL_1.1");
+
+asm(".symver cil_selinuxusers_to_string_pdb, cil_selinuxusers_to_string@");
+asm(".symver cil_selinuxusers_to_string_nopdb, cil_selinuxusers_to_string@@LIBSEPOL_1.1");
+
+asm(".symver cil_filecons_to_string_pdb, cil_filecons_to_string@");
+asm(".symver cil_filecons_to_string_nopdb, cil_filecons_to_string@@LIBSEPOL_1.1");
+#endif
+
+int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = {
+ {64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+ {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+};
+
+static void cil_init_keys(void)
+{
+ /* Initialize CIL Keys into strpool */
+ CIL_KEY_CONS_T1 = cil_strpool_add("t1");
+ CIL_KEY_CONS_T2 = cil_strpool_add("t2");
+ CIL_KEY_CONS_T3 = cil_strpool_add("t3");
+ CIL_KEY_CONS_R1 = cil_strpool_add("r1");
+ CIL_KEY_CONS_R2 = cil_strpool_add("r2");
+ CIL_KEY_CONS_R3 = cil_strpool_add("r3");
+ CIL_KEY_CONS_U1 = cil_strpool_add("u1");
+ CIL_KEY_CONS_U2 = cil_strpool_add("u2");
+ CIL_KEY_CONS_U3 = cil_strpool_add("u3");
+ CIL_KEY_CONS_L1 = cil_strpool_add("l1");
+ CIL_KEY_CONS_L2 = cil_strpool_add("l2");
+ CIL_KEY_CONS_H1 = cil_strpool_add("h1");
+ CIL_KEY_CONS_H2 = cil_strpool_add("h2");
+ CIL_KEY_AND = cil_strpool_add("and");
+ CIL_KEY_OR = cil_strpool_add("or");
+ CIL_KEY_NOT = cil_strpool_add("not");
+ CIL_KEY_EQ = cil_strpool_add("eq");
+ CIL_KEY_NEQ = cil_strpool_add("neq");
+ CIL_KEY_CONS_DOM = cil_strpool_add("dom");
+ CIL_KEY_CONS_DOMBY = cil_strpool_add("domby");
+ CIL_KEY_CONS_INCOMP = cil_strpool_add("incomp");
+ CIL_KEY_CONDTRUE = cil_strpool_add("true");
+ CIL_KEY_CONDFALSE = cil_strpool_add("false");
+ CIL_KEY_SELF = cil_strpool_add("self");
+ CIL_KEY_OBJECT_R = cil_strpool_add("object_r");
+ CIL_KEY_STAR = cil_strpool_add("*");
+ CIL_KEY_UDP = cil_strpool_add("udp");
+ CIL_KEY_TCP = cil_strpool_add("tcp");
+ CIL_KEY_DCCP = cil_strpool_add("dccp");
+ CIL_KEY_AUDITALLOW = cil_strpool_add("auditallow");
+ CIL_KEY_TUNABLEIF = cil_strpool_add("tunableif");
+ CIL_KEY_ALLOW = cil_strpool_add("allow");
+ CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit");
+ CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition");
+ CIL_KEY_TYPECHANGE = cil_strpool_add("typechange");
+ CIL_KEY_CALL = cil_strpool_add("call");
+ CIL_KEY_TUNABLE = cil_strpool_add("tunable");
+ CIL_KEY_XOR = cil_strpool_add("xor");
+ CIL_KEY_ALL = cil_strpool_add("all");
+ CIL_KEY_RANGE = cil_strpool_add("range");
+ CIL_KEY_TYPE = cil_strpool_add("type");
+ CIL_KEY_ROLE = cil_strpool_add("role");
+ CIL_KEY_USER = cil_strpool_add("user");
+ CIL_KEY_USERATTRIBUTE = cil_strpool_add("userattribute");
+ CIL_KEY_USERATTRIBUTESET = cil_strpool_add("userattributeset");
+ CIL_KEY_SENSITIVITY = cil_strpool_add("sensitivity");
+ CIL_KEY_CATEGORY = cil_strpool_add("category");
+ CIL_KEY_CATSET = cil_strpool_add("categoryset");
+ CIL_KEY_LEVEL = cil_strpool_add("level");
+ CIL_KEY_LEVELRANGE = cil_strpool_add("levelrange");
+ CIL_KEY_CLASS = cil_strpool_add("class");
+ CIL_KEY_IPADDR = cil_strpool_add("ipaddr");
+ CIL_KEY_MAP_CLASS = cil_strpool_add("classmap");
+ CIL_KEY_CLASSPERMISSION = cil_strpool_add("classpermission");
+ CIL_KEY_BOOL = cil_strpool_add("boolean");
+ CIL_KEY_STRING = cil_strpool_add("string");
+ CIL_KEY_NAME = cil_strpool_add("name");
+ CIL_KEY_HANDLEUNKNOWN = cil_strpool_add("handleunknown");
+ CIL_KEY_HANDLEUNKNOWN_ALLOW = cil_strpool_add("allow");
+ CIL_KEY_HANDLEUNKNOWN_DENY = cil_strpool_add("deny");
+ CIL_KEY_HANDLEUNKNOWN_REJECT = cil_strpool_add("reject");
+ CIL_KEY_BLOCKINHERIT = cil_strpool_add("blockinherit");
+ CIL_KEY_BLOCKABSTRACT = cil_strpool_add("blockabstract");
+ CIL_KEY_CLASSORDER = cil_strpool_add("classorder");
+ CIL_KEY_CLASSMAPPING = cil_strpool_add("classmapping");
+ CIL_KEY_CLASSPERMISSIONSET = cil_strpool_add("classpermissionset");
+ CIL_KEY_COMMON = cil_strpool_add("common");
+ CIL_KEY_CLASSCOMMON = cil_strpool_add("classcommon");
+ CIL_KEY_SID = cil_strpool_add("sid");
+ CIL_KEY_SIDCONTEXT = cil_strpool_add("sidcontext");
+ CIL_KEY_SIDORDER = cil_strpool_add("sidorder");
+ CIL_KEY_USERLEVEL = cil_strpool_add("userlevel");
+ CIL_KEY_USERRANGE = cil_strpool_add("userrange");
+ CIL_KEY_USERBOUNDS = cil_strpool_add("userbounds");
+ CIL_KEY_USERPREFIX = cil_strpool_add("userprefix");
+ CIL_KEY_SELINUXUSER = cil_strpool_add("selinuxuser");
+ CIL_KEY_SELINUXUSERDEFAULT = cil_strpool_add("selinuxuserdefault");
+ CIL_KEY_TYPEATTRIBUTE = cil_strpool_add("typeattribute");
+ CIL_KEY_TYPEATTRIBUTESET = cil_strpool_add("typeattributeset");
+ CIL_KEY_TYPEALIAS = cil_strpool_add("typealias");
+ CIL_KEY_TYPEALIASACTUAL = cil_strpool_add("typealiasactual");
+ CIL_KEY_TYPEBOUNDS = cil_strpool_add("typebounds");
+ CIL_KEY_TYPEPERMISSIVE = cil_strpool_add("typepermissive");
+ CIL_KEY_RANGETRANSITION = cil_strpool_add("rangetransition");
+ CIL_KEY_USERROLE = cil_strpool_add("userrole");
+ CIL_KEY_ROLETYPE = cil_strpool_add("roletype");
+ CIL_KEY_ROLETRANSITION = cil_strpool_add("roletransition");
+ CIL_KEY_ROLEALLOW = cil_strpool_add("roleallow");
+ CIL_KEY_ROLEATTRIBUTE = cil_strpool_add("roleattribute");
+ CIL_KEY_ROLEATTRIBUTESET = cil_strpool_add("roleattributeset");
+ CIL_KEY_ROLEBOUNDS = cil_strpool_add("rolebounds");
+ CIL_KEY_BOOLEANIF = cil_strpool_add("booleanif");
+ CIL_KEY_NEVERALLOW = cil_strpool_add("neverallow");
+ CIL_KEY_TYPEMEMBER = cil_strpool_add("typemember");
+ CIL_KEY_SENSALIAS = cil_strpool_add("sensitivityalias");
+ CIL_KEY_SENSALIASACTUAL = cil_strpool_add("sensitivityaliasactual");
+ CIL_KEY_CATALIAS = cil_strpool_add("categoryalias");
+ CIL_KEY_CATALIASACTUAL = cil_strpool_add("categoryaliasactual");
+ CIL_KEY_CATORDER = cil_strpool_add("categoryorder");
+ CIL_KEY_SENSITIVITYORDER = cil_strpool_add("sensitivityorder");
+ CIL_KEY_SENSCAT = cil_strpool_add("sensitivitycategory");
+ CIL_KEY_CONSTRAIN = cil_strpool_add("constrain");
+ CIL_KEY_MLSCONSTRAIN = cil_strpool_add("mlsconstrain");
+ CIL_KEY_VALIDATETRANS = cil_strpool_add("validatetrans");
+ CIL_KEY_MLSVALIDATETRANS = cil_strpool_add("mlsvalidatetrans");
+ CIL_KEY_CONTEXT = cil_strpool_add("context");
+ CIL_KEY_FILECON = cil_strpool_add("filecon");
+ CIL_KEY_PORTCON = cil_strpool_add("portcon");
+ CIL_KEY_NODECON = cil_strpool_add("nodecon");
+ CIL_KEY_GENFSCON = cil_strpool_add("genfscon");
+ CIL_KEY_NETIFCON = cil_strpool_add("netifcon");
+ CIL_KEY_PIRQCON = cil_strpool_add("pirqcon");
+ CIL_KEY_IOMEMCON = cil_strpool_add("iomemcon");
+ CIL_KEY_IOPORTCON = cil_strpool_add("ioportcon");
+ CIL_KEY_PCIDEVICECON = cil_strpool_add("pcidevicecon");
+ CIL_KEY_DEVICETREECON = cil_strpool_add("devicetreecon");
+ CIL_KEY_FSUSE = cil_strpool_add("fsuse");
+ CIL_KEY_POLICYCAP = cil_strpool_add("policycap");
+ CIL_KEY_OPTIONAL = cil_strpool_add("optional");
+ CIL_KEY_DEFAULTUSER = cil_strpool_add("defaultuser");
+ CIL_KEY_DEFAULTROLE = cil_strpool_add("defaultrole");
+ CIL_KEY_DEFAULTTYPE = cil_strpool_add("defaulttype");
+ CIL_KEY_MACRO = cil_strpool_add("macro");
+ CIL_KEY_IN = cil_strpool_add("in");
+ CIL_KEY_MLS = cil_strpool_add("mls");
+ CIL_KEY_DEFAULTRANGE = cil_strpool_add("defaultrange");
+ CIL_KEY_GLOB = cil_strpool_add("*");
+ CIL_KEY_FILE = cil_strpool_add("file");
+ CIL_KEY_DIR = cil_strpool_add("dir");
+ CIL_KEY_CHAR = cil_strpool_add("char");
+ CIL_KEY_BLOCK = cil_strpool_add("block");
+ CIL_KEY_SOCKET = cil_strpool_add("socket");
+ CIL_KEY_PIPE = cil_strpool_add("pipe");
+ CIL_KEY_SYMLINK = cil_strpool_add("symlink");
+ CIL_KEY_ANY = cil_strpool_add("any");
+ CIL_KEY_XATTR = cil_strpool_add("xattr");
+ CIL_KEY_TASK = cil_strpool_add("task");
+ CIL_KEY_TRANS = cil_strpool_add("trans");
+ CIL_KEY_SOURCE = cil_strpool_add("source");
+ CIL_KEY_TARGET = cil_strpool_add("target");
+ CIL_KEY_LOW = cil_strpool_add("low");
+ CIL_KEY_HIGH = cil_strpool_add("high");
+ CIL_KEY_LOW_HIGH = cil_strpool_add("low-high");
+ CIL_KEY_ROOT = cil_strpool_add("<root>");
+ CIL_KEY_NODE = cil_strpool_add("<node>");
+ CIL_KEY_PERM = cil_strpool_add("perm");
+ CIL_KEY_ALLOWX = cil_strpool_add("allowx");
+ CIL_KEY_AUDITALLOWX = cil_strpool_add("auditallowx");
+ CIL_KEY_DONTAUDITX = cil_strpool_add("dontauditx");
+ CIL_KEY_NEVERALLOWX = cil_strpool_add("neverallowx");
+ CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx");
+ CIL_KEY_IOCTL = cil_strpool_add("ioctl");
+ CIL_KEY_UNORDERED = cil_strpool_add("unordered");
+ CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>");
+ CIL_KEY_SRC_CIL = cil_strpool_add("<src_cil>");
+ CIL_KEY_SRC_HLL = cil_strpool_add("<src_hll>");
+}
+
+void cil_db_init(struct cil_db **db)
+{
+ *db = cil_malloc(sizeof(**db));
+
+ cil_strpool_init();
+ cil_init_keys();
+
+ cil_tree_init(&(*db)->parse);
+ cil_tree_init(&(*db)->ast);
+ cil_root_init((struct cil_root **)&(*db)->ast->root->data);
+ (*db)->sidorder = NULL;
+ (*db)->classorder = NULL;
+ (*db)->catorder = NULL;
+ (*db)->sensitivityorder = NULL;
+ cil_sort_init(&(*db)->netifcon);
+ cil_sort_init(&(*db)->genfscon);
+ cil_sort_init(&(*db)->filecon);
+ cil_sort_init(&(*db)->nodecon);
+ cil_sort_init(&(*db)->portcon);
+ cil_sort_init(&(*db)->pirqcon);
+ cil_sort_init(&(*db)->iomemcon);
+ cil_sort_init(&(*db)->ioportcon);
+ cil_sort_init(&(*db)->pcidevicecon);
+ cil_sort_init(&(*db)->devicetreecon);
+ cil_sort_init(&(*db)->fsuse);
+ cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM);
+ cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM);
+ cil_list_init(&(*db)->names, CIL_LIST_ITEM);
+
+ cil_type_init(&(*db)->selftype);
+ (*db)->selftype->datum.name = CIL_KEY_SELF;
+ (*db)->selftype->datum.fqn = CIL_KEY_SELF;
+ (*db)->num_types_and_attrs = 0;
+ (*db)->num_classes = 0;
+ (*db)->num_types = 0;
+ (*db)->num_roles = 0;
+ (*db)->num_users = 0;
+ (*db)->num_cats = 0;
+ (*db)->val_to_type = NULL;
+ (*db)->val_to_role = NULL;
+ (*db)->val_to_user = NULL;
+
+ (*db)->disable_dontaudit = CIL_FALSE;
+ (*db)->disable_neverallow = CIL_FALSE;
+ (*db)->preserve_tunables = CIL_FALSE;
+ (*db)->handle_unknown = -1;
+ (*db)->mls = -1;
+ (*db)->target_platform = SEPOL_TARGET_SELINUX;
+ (*db)->policy_version = POLICYDB_VERSION_MAX;
+}
+
+void cil_db_destroy(struct cil_db **db)
+{
+ if (db == NULL || *db == NULL) {
+ return;
+ }
+
+ cil_tree_destroy(&(*db)->parse);
+ cil_tree_destroy(&(*db)->ast);
+ cil_list_destroy(&(*db)->sidorder, CIL_FALSE);
+ cil_list_destroy(&(*db)->classorder, CIL_FALSE);
+ cil_list_destroy(&(*db)->catorder, CIL_FALSE);
+ cil_list_destroy(&(*db)->sensitivityorder, CIL_FALSE);
+ cil_sort_destroy(&(*db)->netifcon);
+ cil_sort_destroy(&(*db)->genfscon);
+ cil_sort_destroy(&(*db)->filecon);
+ cil_sort_destroy(&(*db)->nodecon);
+ cil_sort_destroy(&(*db)->portcon);
+ cil_sort_destroy(&(*db)->pirqcon);
+ cil_sort_destroy(&(*db)->iomemcon);
+ cil_sort_destroy(&(*db)->ioportcon);
+ cil_sort_destroy(&(*db)->pcidevicecon);
+ cil_sort_destroy(&(*db)->devicetreecon);
+ cil_sort_destroy(&(*db)->fsuse);
+ cil_list_destroy(&(*db)->userprefixes, CIL_FALSE);
+ cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE);
+ cil_list_destroy(&(*db)->names, CIL_TRUE);
+
+ cil_destroy_type((*db)->selftype);
+
+ cil_strpool_destroy();
+ free((*db)->val_to_type);
+ free((*db)->val_to_role);
+ free((*db)->val_to_user);
+
+ free(*db);
+ *db = NULL;
+}
+
+void cil_root_init(struct cil_root **root)
+{
+ struct cil_root *r = cil_malloc(sizeof(*r));
+ cil_symtab_array_init(r->symtab, cil_sym_sizes[CIL_SYM_ARRAY_ROOT]);
+
+ *root = r;
+}
+
+void cil_root_destroy(struct cil_root *root)
+{
+ if (root == NULL) {
+ return;
+ }
+ cil_symtab_array_destroy(root->symtab);
+ free(root);
+}
+
+int cil_add_file(cil_db_t *db, char *name, char *data, size_t size)
+{
+ char *buffer = NULL;
+ int rc;
+
+ cil_log(CIL_INFO, "Parsing %s\n", name);
+
+ buffer = cil_malloc(size + 2);
+ memcpy(buffer, data, size);
+ memset(buffer + size, 0, 2);
+
+ rc = cil_parser(name, buffer, size + 2, &db->parse);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to parse %s\n", name);
+ goto exit;
+ }
+
+ free(buffer);
+ buffer = NULL;
+
+ rc = SEPOL_OK;
+
+exit:
+ free(buffer);
+
+ return rc;
+}
+
+#ifdef DISABLE_SYMVER
+int cil_compile(struct cil_db *db)
+#else
+int cil_compile_nopdb(struct cil_db *db)
+#endif
+{
+ int rc = SEPOL_ERR;
+
+ if (db == NULL) {
+ goto exit;
+ }
+
+ cil_log(CIL_INFO, "Building AST from Parse Tree\n");
+ rc = cil_build_ast(db, db->parse->root, db->ast->root);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to build ast\n");
+ goto exit;
+ }
+
+ cil_log(CIL_INFO, "Destroying Parse Tree\n");
+ cil_tree_destroy(&db->parse);
+
+ cil_log(CIL_INFO, "Resolving AST\n");
+ rc = cil_resolve_ast(db, db->ast->root);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to resolve ast\n");
+ goto exit;
+ }
+
+ cil_log(CIL_INFO, "Qualifying Names\n");
+ rc = cil_fqn_qualify(db->ast->root);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to qualify names\n");
+ goto exit;
+ }
+
+ cil_log(CIL_INFO, "Compile post process\n");
+ rc = cil_post_process(db);
+ if (rc != SEPOL_OK ) {
+ cil_log(CIL_INFO, "Post process failed\n");
+ goto exit;
+ }
+
+exit:
+
+ return rc;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_compile_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db)
+{
+ return cil_compile_nopdb(db);
+}
+
+int cil_build_policydb_pdb(cil_db_t *db, sepol_policydb_t *sepol_db)
+{
+ int rc;
+
+ cil_log(CIL_INFO, "Building policy binary\n");
+ rc = cil_binary_create_allocated_pdb(db, sepol_db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to generate binary\n");
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+#endif
+
+#ifdef DISABLE_SYMVER
+int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db)
+#else
+int cil_build_policydb_create_pdb(cil_db_t *db, sepol_policydb_t **sepol_db)
+#endif
+{
+ int rc;
+
+ cil_log(CIL_INFO, "Building policy binary\n");
+ rc = cil_binary_create(db, sepol_db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to generate binary\n");
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+void cil_destroy_data(void **data, enum cil_flavor flavor)
+{
+ if (*data == NULL) {
+ return;
+ }
+
+ switch(flavor) {
+ case CIL_NONE:
+ break;
+ case CIL_ROOT:
+ cil_root_destroy(*data);
+ break;
+ case CIL_NODE:
+ break;
+ case CIL_STRING:
+ break;
+ case CIL_DATUM:
+ break;
+ case CIL_LIST:
+ cil_list_destroy(*data, CIL_FALSE);
+ break;
+ case CIL_LIST_ITEM:
+ break;
+ case CIL_PARAM:
+ cil_destroy_param(*data);
+ break;
+ case CIL_ARGS:
+ cil_destroy_args(*data);
+ break;
+ case CIL_BLOCK:
+ cil_destroy_block(*data);
+ break;
+ case CIL_BLOCKINHERIT:
+ cil_destroy_blockinherit(*data);
+ break;
+ case CIL_BLOCKABSTRACT:
+ cil_destroy_blockabstract(*data);
+ break;
+ case CIL_IN:
+ cil_destroy_in(*data);
+ break;
+ case CIL_MACRO:
+ cil_destroy_macro(*data);
+ break;
+ case CIL_CALL:
+ cil_destroy_call(*data);
+ break;
+ case CIL_OPTIONAL:
+ cil_destroy_optional(*data);
+ break;
+ case CIL_BOOL:
+ cil_destroy_bool(*data);
+ break;
+ case CIL_BOOLEANIF:
+ cil_destroy_boolif(*data);
+ break;
+ case CIL_TUNABLE:
+ cil_destroy_tunable(*data);
+ break;
+ case CIL_TUNABLEIF:
+ cil_destroy_tunif(*data);
+ break;
+ case CIL_CONDBLOCK:
+ cil_destroy_condblock(*data);
+ break;
+ case CIL_CONDTRUE:
+ break;
+ case CIL_CONDFALSE:
+ break;
+ case CIL_PERM:
+ case CIL_MAP_PERM:
+ cil_destroy_perm(*data);
+ break;
+ case CIL_COMMON:
+ case CIL_CLASS:
+ case CIL_MAP_CLASS:
+ cil_destroy_class(*data);
+ break;
+ case CIL_CLASSORDER:
+ cil_destroy_classorder(*data);
+ break;
+ case CIL_CLASSPERMISSION:
+ cil_destroy_classpermission(*data);
+ break;
+ case CIL_CLASSCOMMON:
+ cil_destroy_classcommon(*data);
+ break;
+ case CIL_CLASSMAPPING:
+ cil_destroy_classmapping(*data);
+ break;
+ case CIL_CLASSPERMS:
+ cil_destroy_classperms(*data);
+ break;
+ case CIL_CLASSPERMS_SET:
+ cil_destroy_classperms_set(*data);
+ break;
+ case CIL_CLASSPERMISSIONSET:
+ cil_destroy_classpermissionset(*data);
+ break;
+ case CIL_USER:
+ cil_destroy_user(*data);
+ break;
+ case CIL_USERATTRIBUTE:
+ cil_destroy_userattribute(*data);
+ break;
+ case CIL_USERATTRIBUTESET:
+ cil_destroy_userattributeset(*data);
+ break;
+ case CIL_USERPREFIX:
+ cil_destroy_userprefix(*data);
+ break;
+ case CIL_USERROLE:
+ cil_destroy_userrole(*data);
+ break;
+ case CIL_USERLEVEL:
+ cil_destroy_userlevel(*data);
+ break;
+ case CIL_USERRANGE:
+ cil_destroy_userrange(*data);
+ break;
+ case CIL_USERBOUNDS:
+ cil_destroy_bounds(*data);
+ break;
+ case CIL_SELINUXUSER:
+ case CIL_SELINUXUSERDEFAULT:
+ cil_destroy_selinuxuser(*data);
+ break;
+ case CIL_ROLE:
+ cil_destroy_role(*data);
+ break;
+ case CIL_ROLEATTRIBUTE:
+ cil_destroy_roleattribute(*data);
+ break;
+ case CIL_ROLEATTRIBUTESET:
+ cil_destroy_roleattributeset(*data);
+ break;
+ case CIL_ROLETYPE:
+ cil_destroy_roletype(*data);
+ break;
+ case CIL_ROLEBOUNDS:
+ cil_destroy_bounds(*data);
+ break;
+ case CIL_TYPE:
+ cil_destroy_type(*data);
+ break;
+ case CIL_TYPEATTRIBUTE:
+ cil_destroy_typeattribute(*data);
+ break;
+ case CIL_TYPEALIAS:
+ cil_destroy_alias(*data);
+ break;
+ case CIL_TYPEATTRIBUTESET:
+ cil_destroy_typeattributeset(*data);
+ break;
+ case CIL_TYPEALIASACTUAL:
+ cil_destroy_aliasactual(*data);
+ break;
+ case CIL_TYPEBOUNDS:
+ cil_destroy_bounds(*data);
+ break;
+ case CIL_TYPEPERMISSIVE:
+ cil_destroy_typepermissive(*data);
+ break;
+ case CIL_SENS:
+ cil_destroy_sensitivity(*data);
+ break;
+ case CIL_SENSALIAS:
+ cil_destroy_alias(*data);
+ break;
+ case CIL_SENSALIASACTUAL:
+ cil_destroy_aliasactual(*data);
+ break;
+ case CIL_SENSITIVITYORDER:
+ cil_destroy_sensitivityorder(*data);
+ break;
+ case CIL_SENSCAT:
+ cil_destroy_senscat(*data);
+ break;
+ case CIL_CAT:
+ cil_destroy_category(*data);
+ break;
+ case CIL_CATSET:
+ cil_destroy_catset(*data);
+ break;
+ case CIL_CATALIAS:
+ cil_destroy_alias(*data);
+ break;
+ case CIL_CATALIASACTUAL:
+ cil_destroy_aliasactual(*data);
+ break;
+ case CIL_CATORDER:
+ cil_destroy_catorder(*data);
+ break;
+ case CIL_LEVEL:
+ cil_destroy_level(*data);
+ break;
+ case CIL_LEVELRANGE:
+ cil_destroy_levelrange(*data);
+ break;
+ case CIL_SID:
+ cil_destroy_sid(*data);
+ break;
+ case CIL_SIDORDER:
+ cil_destroy_sidorder(*data);
+ break;
+ case CIL_NAME:
+ cil_destroy_name(*data);
+ break;
+ case CIL_ROLEALLOW:
+ cil_destroy_roleallow(*data);
+ break;
+ case CIL_AVRULE:
+ case CIL_AVRULEX:
+ cil_destroy_avrule(*data);
+ break;
+ case CIL_PERMISSIONX:
+ cil_destroy_permissionx(*data);
+ break;
+ case CIL_ROLETRANSITION:
+ cil_destroy_roletransition(*data);
+ break;
+ case CIL_TYPE_RULE:
+ cil_destroy_type_rule(*data);
+ break;
+ case CIL_NAMETYPETRANSITION:
+ cil_destroy_typetransition(*data);
+ break;
+ case CIL_RANGETRANSITION:
+ cil_destroy_rangetransition(*data);
+ break;
+ case CIL_CONSTRAIN:
+ cil_destroy_constrain(*data);
+ break;
+ case CIL_MLSCONSTRAIN:
+ cil_destroy_constrain(*data);
+ break;
+ case CIL_VALIDATETRANS:
+ case CIL_MLSVALIDATETRANS:
+ cil_destroy_validatetrans(*data);
+ break;
+ case CIL_CONTEXT:
+ cil_destroy_context(*data);
+ break;
+ case CIL_IPADDR:
+ cil_destroy_ipaddr(*data);
+ break;
+ case CIL_SIDCONTEXT:
+ cil_destroy_sidcontext(*data);
+ break;
+ case CIL_FSUSE:
+ cil_destroy_fsuse(*data);
+ break;
+ case CIL_FILECON:
+ cil_destroy_filecon(*data);
+ break;
+ case CIL_PORTCON:
+ cil_destroy_portcon(*data);
+ break;
+ case CIL_NODECON:
+ cil_destroy_nodecon(*data);
+ break;
+ case CIL_GENFSCON:
+ cil_destroy_genfscon(*data);
+ break;
+ case CIL_NETIFCON:
+ cil_destroy_netifcon(*data);
+ break;
+ case CIL_PIRQCON:
+ cil_destroy_pirqcon(*data);
+ break;
+ case CIL_IOMEMCON:
+ cil_destroy_iomemcon(*data);
+ break;
+ case CIL_IOPORTCON:
+ cil_destroy_ioportcon(*data);
+ break;
+ case CIL_PCIDEVICECON:
+ cil_destroy_pcidevicecon(*data);
+ break;
+ case CIL_DEVICETREECON:
+ cil_destroy_devicetreecon(*data);
+ break;
+ case CIL_POLICYCAP:
+ cil_destroy_policycap(*data);
+ break;
+ case CIL_DEFAULTUSER:
+ case CIL_DEFAULTROLE:
+ case CIL_DEFAULTTYPE:
+ cil_destroy_default(*data);
+ break;
+ case CIL_DEFAULTRANGE:
+ cil_destroy_defaultrange(*data);
+ break;
+ case CIL_HANDLEUNKNOWN:
+ cil_destroy_handleunknown(*data);
+ break;
+ case CIL_MLS:
+ cil_destroy_mls(*data);
+ break;
+ case CIL_SRC_INFO:
+ cil_destroy_src_info(*data);
+ break;
+ case CIL_OP:
+ case CIL_CONS_OPERAND:
+ break;
+ default:
+ cil_log(CIL_INFO, "Unknown data flavor: %d\n", flavor);
+ break;
+ }
+
+ *data = NULL;
+}
+
+int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_index)
+{
+ if (flavor < CIL_MIN_DECLARATIVE) {
+ return SEPOL_ERR;
+ }
+
+ switch(flavor) {
+ case CIL_BLOCK:
+ *sym_index = CIL_SYM_BLOCKS;
+ break;
+ case CIL_MACRO:
+ *sym_index = CIL_SYM_BLOCKS;
+ break;
+ case CIL_OPTIONAL:
+ *sym_index = CIL_SYM_BLOCKS;
+ break;
+ case CIL_BOOL:
+ *sym_index = CIL_SYM_BOOLS;
+ break;
+ case CIL_TUNABLE:
+ *sym_index = CIL_SYM_TUNABLES;
+ break;
+ case CIL_PERM:
+ case CIL_MAP_PERM:
+ *sym_index = CIL_SYM_PERMS;
+ break;
+ case CIL_COMMON:
+ *sym_index = CIL_SYM_COMMONS;
+ break;
+ case CIL_CLASS:
+ case CIL_MAP_CLASS:
+ *sym_index = CIL_SYM_CLASSES;
+ break;
+ case CIL_CLASSPERMISSION:
+ case CIL_CLASSPERMISSIONSET:
+ *sym_index = CIL_SYM_CLASSPERMSETS;
+ break;
+ case CIL_USER:
+ case CIL_USERATTRIBUTE:
+ *sym_index = CIL_SYM_USERS;
+ break;
+ case CIL_ROLE:
+ case CIL_ROLEATTRIBUTE:
+ *sym_index = CIL_SYM_ROLES;
+ break;
+ case CIL_TYPE:
+ case CIL_TYPEALIAS:
+ case CIL_TYPEATTRIBUTE:
+ *sym_index = CIL_SYM_TYPES;
+ break;
+ case CIL_SENS:
+ case CIL_SENSALIAS:
+ *sym_index = CIL_SYM_SENS;
+ break;
+ case CIL_CAT:
+ case CIL_CATSET:
+ case CIL_CATALIAS:
+ *sym_index = CIL_SYM_CATS;
+ break;
+ case CIL_LEVEL:
+ *sym_index = CIL_SYM_LEVELS;
+ break;
+ case CIL_LEVELRANGE:
+ *sym_index = CIL_SYM_LEVELRANGES;
+ break;
+ case CIL_SID:
+ *sym_index = CIL_SYM_SIDS;
+ break;
+ case CIL_NAME:
+ *sym_index = CIL_SYM_NAMES;
+ break;
+ case CIL_CONTEXT:
+ *sym_index = CIL_SYM_CONTEXTS;
+ break;
+ case CIL_IPADDR:
+ *sym_index = CIL_SYM_IPADDRS;
+ break;
+ case CIL_POLICYCAP:
+ *sym_index = CIL_SYM_POLICYCAPS;
+ break;
+ case CIL_PERMISSIONX:
+ *sym_index = CIL_SYM_PERMX;
+ break;
+ default:
+ *sym_index = CIL_SYM_UNKNOWN;
+ cil_log(CIL_INFO, "Failed to find flavor: %d\n", flavor);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+const char * cil_node_to_string(struct cil_tree_node *node)
+{
+ switch (node->flavor) {
+ case CIL_NONE:
+ return "<none>";
+ case CIL_ROOT:
+ return CIL_KEY_ROOT;
+ case CIL_NODE:
+ return CIL_KEY_NODE;
+ case CIL_STRING:
+ return "string";
+ case CIL_DATUM:
+ return "<datum>";
+ case CIL_LIST:
+ return "<list>";
+ case CIL_LIST_ITEM:
+ return "<list_item>";
+ case CIL_PARAM:
+ return "<param>";
+ case CIL_ARGS:
+ return "<args>";
+ case CIL_BLOCK:
+ return CIL_KEY_BLOCK;
+ case CIL_BLOCKINHERIT:
+ return CIL_KEY_BLOCKINHERIT;
+ case CIL_BLOCKABSTRACT:
+ return CIL_KEY_BLOCKABSTRACT;
+ case CIL_IN:
+ return CIL_KEY_IN;
+ case CIL_MACRO:
+ return CIL_KEY_MACRO;
+ case CIL_CALL:
+ return CIL_KEY_CALL;
+ case CIL_OPTIONAL:
+ return CIL_KEY_OPTIONAL;
+ case CIL_BOOL:
+ return CIL_KEY_BOOL;
+ case CIL_BOOLEANIF:
+ return CIL_KEY_BOOLEANIF;
+ case CIL_TUNABLE:
+ return CIL_KEY_TUNABLE;
+ case CIL_TUNABLEIF:
+ return CIL_KEY_TUNABLEIF;
+ case CIL_CONDBLOCK:
+ switch (((struct cil_condblock*)node->data)->flavor) {
+ case CIL_CONDTRUE:
+ return CIL_KEY_CONDTRUE;
+ case CIL_CONDFALSE:
+ return CIL_KEY_CONDFALSE;
+ default:
+ break;
+ }
+ break;
+ case CIL_CONDTRUE:
+ return CIL_KEY_CONDTRUE;
+ case CIL_CONDFALSE:
+ return CIL_KEY_CONDFALSE;
+ case CIL_PERM:
+ return CIL_KEY_PERM;
+ case CIL_COMMON:
+ return CIL_KEY_COMMON;
+ case CIL_CLASS:
+ return CIL_KEY_CLASS;
+ case CIL_CLASSORDER:
+ return CIL_KEY_CLASSORDER;
+ case CIL_MAP_CLASS:
+ return CIL_KEY_MAP_CLASS;
+ case CIL_CLASSPERMISSION:
+ return CIL_KEY_CLASSPERMISSION;
+ case CIL_CLASSCOMMON:
+ return CIL_KEY_CLASSCOMMON;
+ case CIL_CLASSMAPPING:
+ return CIL_KEY_CLASSMAPPING;
+ case CIL_CLASSPERMISSIONSET:
+ return CIL_KEY_CLASSPERMISSIONSET;
+ case CIL_USER:
+ return CIL_KEY_USER;
+ case CIL_USERATTRIBUTE:
+ return CIL_KEY_USERATTRIBUTE;
+ case CIL_USERATTRIBUTESET:
+ return CIL_KEY_USERATTRIBUTESET;
+ case CIL_USERPREFIX:
+ return CIL_KEY_USERPREFIX;
+ case CIL_USERROLE:
+ return CIL_KEY_USERROLE;
+ case CIL_USERLEVEL:
+ return CIL_KEY_USERLEVEL;
+ case CIL_USERRANGE:
+ return CIL_KEY_USERRANGE;
+ case CIL_USERBOUNDS:
+ return CIL_KEY_USERBOUNDS;
+ case CIL_SELINUXUSER:
+ return CIL_KEY_SELINUXUSER;
+ case CIL_SELINUXUSERDEFAULT:
+ return CIL_KEY_SELINUXUSERDEFAULT;
+ case CIL_ROLE:
+ return CIL_KEY_ROLE;
+ case CIL_ROLEATTRIBUTE:
+ return CIL_KEY_ROLEATTRIBUTE;
+ case CIL_ROLEATTRIBUTESET:
+ return CIL_KEY_ROLEATTRIBUTESET;
+ case CIL_ROLETYPE:
+ return CIL_KEY_ROLETYPE;
+ case CIL_ROLEBOUNDS:
+ return CIL_KEY_ROLEBOUNDS;
+ case CIL_TYPE:
+ return CIL_KEY_TYPE;
+ case CIL_TYPEATTRIBUTE:
+ return CIL_KEY_TYPEATTRIBUTE;
+ case CIL_TYPEALIAS:
+ return CIL_KEY_TYPEALIAS;
+ case CIL_TYPEATTRIBUTESET:
+ return CIL_KEY_TYPEATTRIBUTESET;
+ case CIL_TYPEALIASACTUAL:
+ return CIL_KEY_TYPEALIASACTUAL;
+ case CIL_TYPEBOUNDS:
+ return CIL_KEY_TYPEBOUNDS;
+ case CIL_TYPEPERMISSIVE:
+ return CIL_KEY_TYPEPERMISSIVE;
+ case CIL_SENS:
+ return CIL_KEY_SENSITIVITY;
+ case CIL_SENSALIAS:
+ return CIL_KEY_SENSALIAS;
+ case CIL_SENSALIASACTUAL:
+ return CIL_KEY_SENSALIASACTUAL;
+ case CIL_SENSITIVITYORDER:
+ return CIL_KEY_SENSITIVITYORDER;
+ case CIL_SENSCAT:
+ return CIL_KEY_SENSCAT;
+ case CIL_CAT:
+ return CIL_KEY_CATEGORY;
+ case CIL_CATSET:
+ return CIL_KEY_CATSET;
+ case CIL_CATALIAS:
+ return CIL_KEY_CATALIAS;
+ case CIL_CATALIASACTUAL:
+ return CIL_KEY_CATALIASACTUAL;
+ case CIL_CATORDER:
+ return CIL_KEY_CATORDER;
+ case CIL_LEVEL:
+ return CIL_KEY_LEVEL;
+ case CIL_LEVELRANGE:
+ return CIL_KEY_LEVELRANGE;
+ case CIL_SID:
+ return CIL_KEY_SID;
+ case CIL_SIDORDER:
+ return CIL_KEY_SIDORDER;
+ case CIL_NAME:
+ return CIL_KEY_NAME;
+ case CIL_ROLEALLOW:
+ return CIL_KEY_ROLEALLOW;
+ case CIL_AVRULE:
+ switch (((struct cil_avrule *)node->data)->rule_kind) {
+ case CIL_AVRULE_ALLOWED:
+ return CIL_KEY_ALLOW;
+ case CIL_AVRULE_AUDITALLOW:
+ return CIL_KEY_AUDITALLOW;
+ case CIL_AVRULE_DONTAUDIT:
+ return CIL_KEY_DONTAUDIT;
+ case CIL_AVRULE_NEVERALLOW:
+ return CIL_KEY_NEVERALLOW;
+ default:
+ break;
+ }
+ break;
+ case CIL_AVRULEX:
+ switch (((struct cil_avrule *)node->data)->rule_kind) {
+ case CIL_AVRULE_ALLOWED:
+ return CIL_KEY_ALLOWX;
+ case CIL_AVRULE_AUDITALLOW:
+ return CIL_KEY_AUDITALLOWX;
+ case CIL_AVRULE_DONTAUDIT:
+ return CIL_KEY_DONTAUDITX;
+ case CIL_AVRULE_NEVERALLOW:
+ return CIL_KEY_NEVERALLOWX;
+ default:
+ break;
+ }
+ break;
+ case CIL_PERMISSIONX:
+ return CIL_KEY_PERMISSIONX;
+ case CIL_ROLETRANSITION:
+ return CIL_KEY_ROLETRANSITION;
+ case CIL_TYPE_RULE:
+ switch (((struct cil_type_rule *)node->data)->rule_kind) {
+ case CIL_TYPE_TRANSITION:
+ return CIL_KEY_TYPETRANSITION;
+ case CIL_TYPE_MEMBER:
+ return CIL_KEY_TYPEMEMBER;
+ case CIL_TYPE_CHANGE:
+ return CIL_KEY_TYPECHANGE;
+ default:
+ break;
+ }
+ break;
+ case CIL_NAMETYPETRANSITION:
+ return CIL_KEY_TYPETRANSITION;
+ case CIL_RANGETRANSITION:
+ return CIL_KEY_RANGETRANSITION;
+ case CIL_CONSTRAIN:
+ return CIL_KEY_CONSTRAIN;
+ case CIL_MLSCONSTRAIN:
+ return CIL_KEY_MLSCONSTRAIN;
+ case CIL_VALIDATETRANS:
+ return CIL_KEY_VALIDATETRANS;
+ case CIL_MLSVALIDATETRANS:
+ return CIL_KEY_MLSVALIDATETRANS;
+ case CIL_CONTEXT:
+ return CIL_KEY_CONTEXT;
+ case CIL_IPADDR:
+ return CIL_KEY_IPADDR;
+ case CIL_SIDCONTEXT:
+ return CIL_KEY_SIDCONTEXT;
+ case CIL_FSUSE:
+ return CIL_KEY_FSUSE;
+ case CIL_FILECON:
+ return CIL_KEY_FILECON;
+ case CIL_PORTCON:
+ return CIL_KEY_PORTCON;
+ case CIL_NODECON:
+ return CIL_KEY_NODECON;
+ case CIL_GENFSCON:
+ return CIL_KEY_GENFSCON;
+ case CIL_NETIFCON:
+ return CIL_KEY_NETIFCON;
+ case CIL_PIRQCON:
+ return CIL_KEY_PIRQCON;
+ case CIL_IOMEMCON:
+ return CIL_KEY_IOMEMCON;
+ case CIL_IOPORTCON:
+ return CIL_KEY_IOPORTCON;
+ case CIL_PCIDEVICECON:
+ return CIL_KEY_PCIDEVICECON;
+ case CIL_DEVICETREECON:
+ return CIL_KEY_DEVICETREECON;
+ case CIL_POLICYCAP:
+ return CIL_KEY_POLICYCAP;
+ case CIL_DEFAULTUSER:
+ return CIL_KEY_DEFAULTUSER;
+ case CIL_DEFAULTROLE:
+ return CIL_KEY_DEFAULTROLE;
+ case CIL_DEFAULTTYPE:
+ return CIL_KEY_DEFAULTTYPE;
+ case CIL_DEFAULTRANGE:
+ return CIL_KEY_DEFAULTRANGE;
+ case CIL_HANDLEUNKNOWN:
+ return CIL_KEY_HANDLEUNKNOWN;
+ case CIL_MLS:
+ return CIL_KEY_MLS;
+ case CIL_SRC_INFO:
+ return CIL_KEY_SRC_INFO;
+ case CIL_ALL:
+ return CIL_KEY_ALL;
+ case CIL_RANGE:
+ return CIL_KEY_RANGE;
+ case CIL_AND:
+ return CIL_KEY_AND;
+ case CIL_OR:
+ return CIL_KEY_OR;
+ case CIL_XOR:
+ return CIL_KEY_XOR;
+ case CIL_NOT:
+ return CIL_KEY_NOT;
+ case CIL_EQ:
+ return CIL_KEY_EQ;
+ case CIL_NEQ:
+ return CIL_KEY_NEQ;
+ case CIL_CONS_DOM:
+ return CIL_KEY_CONS_DOM;
+ case CIL_CONS_DOMBY:
+ return CIL_KEY_CONS_DOMBY;
+ case CIL_CONS_INCOMP:
+ return CIL_KEY_CONS_INCOMP;
+ case CIL_CONS_U1:
+ return CIL_KEY_CONS_U1;
+ case CIL_CONS_U2:
+ return CIL_KEY_CONS_U2;
+ case CIL_CONS_U3:
+ return CIL_KEY_CONS_U3;
+ case CIL_CONS_T1:
+ return CIL_KEY_CONS_T1;
+ case CIL_CONS_T2:
+ return CIL_KEY_CONS_T2;
+ case CIL_CONS_T3:
+ return CIL_KEY_CONS_T3;
+ case CIL_CONS_R1:
+ return CIL_KEY_CONS_R1;
+ case CIL_CONS_R2:
+ return CIL_KEY_CONS_R2;
+ case CIL_CONS_R3:
+ return CIL_KEY_CONS_R3;
+ case CIL_CONS_L1:
+ return CIL_KEY_CONS_L1;
+ case CIL_CONS_L2:
+ return CIL_KEY_CONS_L2;
+ case CIL_CONS_H1:
+ return CIL_KEY_CONS_H1;
+ case CIL_CONS_H2:
+ return CIL_KEY_CONS_H2;
+
+ default:
+ break;
+ }
+
+ return "<unknown>";
+}
+
+#ifdef DISABLE_SYMVER
+int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_userprefixes_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+ int rc = SEPOL_ERR;
+ size_t str_len = 0;
+ int buf_pos = 0;
+ char *str_tmp = NULL;
+ struct cil_list_item *curr;
+ struct cil_userprefix *userprefix = NULL;
+ struct cil_user *user = NULL;
+
+ *out = NULL;
+
+ if (db->userprefixes->head == NULL) {
+ rc = SEPOL_OK;
+ *size = 0;
+ goto exit;
+ }
+
+ cil_list_for_each(curr, db->userprefixes) {
+ userprefix = curr->data;
+ user = userprefix->user;
+ str_len += strlen("user ") + strlen(user->datum.fqn) + strlen(" prefix ") + strlen(userprefix->prefix_str) + 2;
+ }
+
+ *size = str_len * sizeof(char);
+ str_len++;
+ str_tmp = cil_malloc(str_len * sizeof(char));
+ *out = str_tmp;
+
+ cil_list_for_each(curr, db->userprefixes) {
+ userprefix = curr->data;
+ user = userprefix->user;
+
+ buf_pos = snprintf(str_tmp, str_len, "user %s prefix %s;\n", user->datum.fqn,
+ userprefix->prefix_str);
+ str_len -= buf_pos;
+ str_tmp += buf_pos;
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+
+}
+
+#ifndef DISABLE_SYMVER
+int cil_userprefixes_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+ return cil_userprefixes_to_string_nopdb(db, out, size);
+}
+#endif
+
+static int cil_cats_to_ebitmap(struct cil_cats *cats, struct ebitmap* cats_ebitmap)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *i;
+ struct cil_list_item *j;
+ struct cil_cat* cat;
+ struct cil_catset *cs;
+ struct cil_tree_node *node;
+
+ if (cats == NULL) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ cil_list_for_each(i, cats->datum_expr) {
+ node = DATUM(i->data)->nodes->head->data;
+ if (node->flavor == CIL_CATSET) {
+ cs = (struct cil_catset*)i->data;
+ cil_list_for_each(j, cs->cats->datum_expr) {
+ cat = (struct cil_cat*)j->data;
+ rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ cat = (struct cil_cat*)i->data;
+ rc = ebitmap_set_bit(cats_ebitmap, cat->value, 1);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int cil_level_equals(struct cil_level *low, struct cil_level *high)
+{
+ int rc;
+ struct ebitmap elow;
+ struct ebitmap ehigh;
+
+ if (strcmp(low->sens->datum.fqn, high->sens->datum.fqn)) {
+ rc = 0;
+ goto exit;
+ }
+
+ ebitmap_init(&elow);
+ ebitmap_init(&ehigh);
+
+ rc = cil_cats_to_ebitmap(low->cats, &elow);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_cats_to_ebitmap(high->cats, &ehigh);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return ebitmap_cmp(&elow, &ehigh);
+
+exit:
+ return rc;
+}
+
+static int __cil_level_strlen(struct cil_level *lvl)
+{
+ struct cil_list_item *item;
+ struct cil_cats *cats = lvl->cats;
+ int str_len = 0;
+ char *str1 = NULL;
+ char *str2 = NULL;
+ int first = -1;
+ int last = -1;
+
+ str_len += strlen(lvl->sens->datum.fqn);
+
+ if (cats && cats->datum_expr != NULL) {
+ str_len++; /* initial ":" */
+ cil_list_for_each(item, cats->datum_expr) {
+ struct cil_cat *cat = item->data;
+ if (first == -1) {
+ str1 = cat->datum.fqn;
+ first = cat->value;
+ last = first;
+ } else if (cat->value == last + 1) {
+ last++;
+ str2 = cat->datum.fqn;
+ } else {
+ if (first == last) {
+ str_len += strlen(str1) + strlen(cat->datum.fqn) + 1;
+ } else if (last == first + 1) {
+ str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2;
+ } else {
+ str_len += strlen(str1) + strlen(str2) + strlen(cat->datum.fqn) + 2;
+ }
+ first = -1;
+ last = -1;
+ if (item->next != NULL) {
+ str_len++; /* space for "," after */
+ }
+ }
+ }
+ if (first != -1) {
+ if (first == last) {
+ str_len += strlen(str1);
+ } else if (last == first + 1) {
+ str_len += strlen(str1) + strlen(str2) + 1;
+ } else {
+ str_len += strlen(str1) + strlen(str2) + 1;
+ }
+ }
+ }
+
+ return str_len;
+}
+
+static int __cil_level_to_string(struct cil_level *lvl, char *out)
+{
+ struct cil_list_item *item;
+ struct cil_cats *cats = lvl->cats;
+ int buf_pos = 0;
+ char *str_tmp = out;
+ char *str1 = NULL;
+ char *str2 = NULL;
+ int first = -1;
+ int last = -1;
+
+ buf_pos = sprintf(str_tmp, "%s", lvl->sens->datum.fqn);
+ str_tmp += buf_pos;
+
+ if (cats && cats->datum_expr != NULL) {
+ buf_pos = sprintf(str_tmp, ":");
+ str_tmp += buf_pos;
+
+ cil_list_for_each(item, cats->datum_expr) {
+ struct cil_cat *cat = item->data;
+ if (first == -1) {
+ str1 = cat->datum.fqn;
+ first = cat->value;
+ last = first;
+ } else if (cat->value == last + 1) {
+ last++;
+ str2 = cat->datum.fqn;
+ } else {
+ if (first == last) {
+ buf_pos = sprintf(str_tmp, "%s,%s", str1, cat->datum.fqn);
+ str_tmp += buf_pos;
+ } else if (last == first + 1) {
+ buf_pos = sprintf(str_tmp, "%s,%s,%s", str1, str2, cat->datum.fqn);
+ str_tmp += buf_pos;
+ } else {
+ buf_pos = sprintf(str_tmp, "%s.%s,%s",str1, str2, cat->datum.fqn);
+ str_tmp += buf_pos;
+ }
+ first = -1;
+ last = -1;
+ if (item->next != NULL) {
+ buf_pos = sprintf(str_tmp, ",");
+ str_tmp += buf_pos;
+ }
+ }
+ }
+ if (first != -1) {
+ if (first == last) {
+ buf_pos = sprintf(str_tmp, "%s", str1);
+ str_tmp += buf_pos;
+ } else if (last == first + 1) {
+ buf_pos = sprintf(str_tmp, "%s,%s", str1, str2);
+ str_tmp += buf_pos;
+ } else {
+ buf_pos = sprintf(str_tmp, "%s.%s",str1, str2);
+ str_tmp += buf_pos;
+ }
+ }
+ }
+
+ return str_tmp - out;
+}
+
+#ifdef DISABLE_SYMVER
+int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_selinuxusers_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+ size_t str_len = 0;
+ int buf_pos = 0;
+ char *str_tmp = NULL;
+ struct cil_list_item *curr;
+
+ if (db->selinuxusers->head == NULL) {
+ *size = 0;
+ *out = NULL;
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(curr, db->selinuxusers) {
+ struct cil_selinuxuser *selinuxuser = curr->data;
+ struct cil_user *user = selinuxuser->user;
+
+ str_len += strlen(selinuxuser->name_str) + strlen(user->datum.fqn) + 1;
+
+ if (db->mls == CIL_TRUE) {
+ struct cil_levelrange *range = selinuxuser->range;
+ str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2;
+ }
+
+ str_len++;
+ }
+
+ *size = str_len * sizeof(char);
+ str_tmp = cil_malloc(*size+1);
+ *out = str_tmp;
+
+ for(curr = db->selinuxusers->head; curr != NULL; curr = curr->next) {
+ struct cil_selinuxuser *selinuxuser = curr->data;
+ struct cil_user *user = selinuxuser->user;
+
+ buf_pos = sprintf(str_tmp, "%s:%s", selinuxuser->name_str, user->datum.fqn);
+ str_tmp += buf_pos;
+
+ if (db->mls == CIL_TRUE) {
+ struct cil_levelrange *range = selinuxuser->range;
+ buf_pos = sprintf(str_tmp, ":");
+ str_tmp += buf_pos;
+ buf_pos = __cil_level_to_string(range->low, str_tmp);
+ str_tmp += buf_pos;
+ buf_pos = sprintf(str_tmp, "-");
+ str_tmp += buf_pos;
+ buf_pos = __cil_level_to_string(range->high, str_tmp);
+ str_tmp += buf_pos;
+ }
+
+ buf_pos = sprintf(str_tmp, "\n");
+ str_tmp += buf_pos;
+ }
+
+ return SEPOL_OK;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_selinuxusers_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+ return cil_selinuxusers_to_string_nopdb(db, out, size);
+}
+#endif
+
+#ifdef DISABLE_SYMVER
+int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size)
+#else
+int cil_filecons_to_string_nopdb(struct cil_db *db, char **out, size_t *size)
+#endif
+{
+ uint32_t i = 0;
+ int buf_pos = 0;
+ size_t str_len = 0;
+ char *str_tmp = NULL;
+ struct cil_sort *filecons = db->filecon;
+
+ for (i = 0; i < filecons->count; i++) {
+ struct cil_filecon *filecon = filecons->array[i];
+ struct cil_context *ctx = filecon->context;
+
+ str_len += strlen(filecon->path_str);
+
+ if (filecon->type != CIL_FILECON_ANY) {
+ /* If a type is specified,
+ +2 for type string, +1 for tab */
+ str_len += 3;
+ }
+
+ if (ctx != NULL) {
+ struct cil_user *user = ctx->user;
+ struct cil_role *role = ctx->role;
+ struct cil_type *type = ctx->type;
+
+ str_len += (strlen(user->datum.fqn) + strlen(role->datum.fqn) + strlen(type->datum.fqn) + 3);
+
+ if (db->mls == CIL_TRUE) {
+ struct cil_levelrange *range = ctx->range;
+ if (cil_level_equals(range->low, range->high)) {
+ str_len += __cil_level_strlen(range->low) + 1;
+ } else {
+ str_len += __cil_level_strlen(range->low) + __cil_level_strlen(range->high) + 2;
+ }
+ }
+ } else {
+ str_len += strlen("\t<<none>>");
+ }
+
+ str_len++;
+ }
+
+ *size = str_len * sizeof(char);
+ str_tmp = cil_malloc(*size+1);
+ *out = str_tmp;
+
+ for (i = 0; i < filecons->count; i++) {
+ struct cil_filecon *filecon = filecons->array[i];
+ struct cil_context *ctx = filecon->context;
+ const char *str_type = NULL;
+
+ buf_pos = sprintf(str_tmp, "%s", filecon->path_str);
+ str_tmp += buf_pos;
+
+ switch(filecon->type) {
+ case CIL_FILECON_FILE:
+ str_type = "\t--";
+ break;
+ case CIL_FILECON_DIR:
+ str_type = "\t-d";
+ break;
+ case CIL_FILECON_CHAR:
+ str_type = "\t-c";
+ break;
+ case CIL_FILECON_BLOCK:
+ str_type = "\t-b";
+ break;
+ case CIL_FILECON_SOCKET:
+ str_type = "\t-s";
+ break;
+ case CIL_FILECON_PIPE:
+ str_type = "\t-p";
+ break;
+ case CIL_FILECON_SYMLINK:
+ str_type = "\t-l";
+ break;
+ default:
+ str_type = "";
+ break;
+ }
+ buf_pos = sprintf(str_tmp, "%s", str_type);
+ str_tmp += buf_pos;
+
+ if (ctx != NULL) {
+ struct cil_user *user = ctx->user;
+ struct cil_role *role = ctx->role;
+ struct cil_type *type = ctx->type;
+
+ buf_pos = sprintf(str_tmp, "\t%s:%s:%s", user->datum.fqn, role->datum.fqn,
+ type->datum.fqn);
+ str_tmp += buf_pos;
+
+ if (db->mls == CIL_TRUE) {
+ struct cil_levelrange *range = ctx->range;
+ buf_pos = sprintf(str_tmp, ":");
+ str_tmp += buf_pos;
+ buf_pos = __cil_level_to_string(range->low, str_tmp);
+ str_tmp += buf_pos;
+
+ if (!cil_level_equals(range->low, range->high)) {
+ buf_pos = sprintf(str_tmp, "-");
+ str_tmp += buf_pos;
+ buf_pos = __cil_level_to_string(range->high, str_tmp);
+ str_tmp += buf_pos;
+ }
+ }
+ } else {
+ buf_pos = sprintf(str_tmp, "\t<<none>>");
+ str_tmp += buf_pos;
+ }
+
+ buf_pos = sprintf(str_tmp, "\n");
+ str_tmp += buf_pos;
+ }
+
+ return SEPOL_OK;
+}
+
+#ifndef DISABLE_SYMVER
+int cil_filecons_to_string_pdb(struct cil_db *db, __attribute__((unused)) sepol_policydb_t *sepol_db, char **out, size_t *size)
+{
+ return cil_filecons_to_string_nopdb(db, out, size);
+}
+#endif
+
+void cil_set_disable_dontaudit(struct cil_db *db, int disable_dontaudit)
+{
+ db->disable_dontaudit = disable_dontaudit;
+}
+
+void cil_set_disable_neverallow(struct cil_db *db, int disable_neverallow)
+{
+ db->disable_neverallow = disable_neverallow;
+}
+
+void cil_set_preserve_tunables(struct cil_db *db, int preserve_tunables)
+{
+ db->preserve_tunables = preserve_tunables;
+}
+
+int cil_set_handle_unknown(struct cil_db *db, int handle_unknown)
+{
+ int rc = 0;
+
+ switch (handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ case SEPOL_REJECT_UNKNOWN:
+ case SEPOL_ALLOW_UNKNOWN:
+ db->handle_unknown = handle_unknown;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown value for handle-unknown: %i\n", handle_unknown);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+void cil_set_mls(struct cil_db *db, int mls)
+{
+ db->mls = mls;
+}
+
+void cil_set_target_platform(struct cil_db *db, int target_platform)
+{
+ db->target_platform = target_platform;
+}
+
+void cil_set_policy_version(struct cil_db *db, int policy_version)
+{
+ db->policy_version = policy_version;
+}
+
+void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM])
+{
+ uint32_t i = 0;
+ for (i = 0; i < CIL_SYM_NUM; i++) {
+ cil_symtab_init(&symtab[i], symtab_sizes[i]);
+ }
+}
+
+void cil_symtab_array_destroy(symtab_t symtab[])
+{
+ int i = 0;
+ for (i = 0; i < CIL_SYM_NUM; i++) {
+ cil_symtab_destroy(&symtab[i]);
+ }
+}
+
+void cil_destroy_ast_symtabs(struct cil_tree_node *current)
+{
+ while (current) {
+ switch (current->flavor) {
+ case CIL_BLOCK:
+ cil_symtab_array_destroy(((struct cil_block*)current->data)->symtab);
+ break;
+ case CIL_IN:
+ cil_symtab_array_destroy(((struct cil_in*)current->data)->symtab);
+ break;
+ case CIL_CLASS:
+ case CIL_COMMON:
+ case CIL_MAP_CLASS:
+ cil_symtab_destroy(&((struct cil_class*)current->data)->perms);
+ break;
+ case CIL_MACRO:
+ cil_symtab_array_destroy(((struct cil_macro*)current->data)->symtab);
+ break;
+ case CIL_CONDBLOCK:
+ cil_symtab_array_destroy(((struct cil_condblock*)current->data)->symtab);
+ break;
+ default:
+ break;
+ }
+
+ if (current->cl_head) {
+ cil_destroy_ast_symtabs(current->cl_head);
+ }
+
+ current = current->next;
+ }
+}
+
+int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index)
+{
+ struct cil_tree_node *node = ast_node;
+ *symtab = NULL;
+
+ if (sym_index == CIL_SYM_PERMS) {
+ /* Class statements are not blocks, so the passed node should be the class */
+ if (node->flavor == CIL_CLASS || node->flavor == CIL_MAP_CLASS ||
+ node->flavor == CIL_COMMON) {
+ *symtab = &((struct cil_class*)node->data)->perms;
+ return SEPOL_OK;
+ }
+ goto exit;
+ }
+
+ if (sym_index < CIL_SYM_BLOCKS || sym_index >= CIL_SYM_NUM) {
+ cil_log(CIL_ERR, "Invalid symtab type\n");
+ goto exit;
+ }
+
+ while (node != NULL && *symtab == NULL) {
+ switch (node->flavor) {
+ case CIL_ROOT:
+ *symtab = &((struct cil_root *)node->data)->symtab[sym_index];
+ break;
+ case CIL_BLOCK:
+ *symtab = &((struct cil_block*)node->data)->symtab[sym_index];
+ break;
+ case CIL_MACRO:
+ *symtab = &((struct cil_macro*)node->data)->symtab[sym_index];
+ break;
+ case CIL_IN:
+ /* In blocks only exist before resolving the AST */
+ *symtab = &((struct cil_in*)node->data)->symtab[sym_index];
+ break;
+ case CIL_CONDBLOCK: {
+ if (node->parent->flavor == CIL_TUNABLEIF) {
+ /* Cond blocks only exist before resolving the AST */
+ *symtab = &((struct cil_condblock*)node->data)->symtab[sym_index];
+ } else if (node->parent->flavor == CIL_BOOLEANIF) {
+ node = node->parent->parent;
+ }
+ break;
+ }
+ default:
+ node = node->parent;
+ }
+ }
+
+ if (*symtab == NULL) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(ast_node, CIL_ERR, "Failed to get symtab from node");
+ return SEPOL_ERR;
+}
+
+void cil_sort_init(struct cil_sort **sort)
+{
+ *sort = cil_malloc(sizeof(**sort));
+
+ (*sort)->flavor = CIL_NONE;
+ (*sort)->count = 0;
+ (*sort)->index = 0;
+ (*sort)->array = NULL;
+}
+
+void cil_sort_destroy(struct cil_sort **sort)
+{
+ (*sort)->flavor = CIL_NONE;
+ (*sort)->count = 0;
+ (*sort)->index = 0;
+ if ((*sort)->array != NULL) {
+ free((*sort)->array);
+ }
+ (*sort)->array = NULL;
+
+ free(*sort);
+ *sort = NULL;
+}
+
+void cil_netifcon_init(struct cil_netifcon **netifcon)
+{
+ *netifcon = cil_malloc(sizeof(**netifcon));
+
+ (*netifcon)->interface_str = NULL;
+ (*netifcon)->if_context_str = NULL;
+ (*netifcon)->if_context = NULL;
+ (*netifcon)->packet_context_str = NULL;
+ (*netifcon)->packet_context = NULL;
+ (*netifcon)->context_str = NULL;
+}
+
+void cil_context_init(struct cil_context **context)
+{
+ *context = cil_malloc(sizeof(**context));
+
+ cil_symtab_datum_init(&(*context)->datum);
+ (*context)->user_str = NULL;
+ (*context)->user = NULL;
+ (*context)->role_str = NULL;
+ (*context)->role = NULL;
+ (*context)->type_str = NULL;
+ (*context)->type = NULL;
+ (*context)->range_str = NULL;
+ (*context)->range = NULL;
+}
+
+void cil_level_init(struct cil_level **level)
+{
+ *level = cil_malloc(sizeof(**level));
+
+ cil_symtab_datum_init(&(*level)->datum);
+ (*level)->sens_str = NULL;
+ (*level)->sens = NULL;
+ (*level)->cats = NULL;
+}
+
+void cil_levelrange_init(struct cil_levelrange **range)
+{
+ *range = cil_malloc(sizeof(**range));
+
+ cil_symtab_datum_init(&(*range)->datum);
+ (*range)->low_str = NULL;
+ (*range)->low = NULL;
+ (*range)->high_str = NULL;
+ (*range)->high = NULL;
+}
+
+void cil_sens_init(struct cil_sens **sens)
+{
+ *sens = cil_malloc(sizeof(**sens));
+
+ cil_symtab_datum_init(&(*sens)->datum);
+
+ (*sens)->cats_list = NULL;
+
+ (*sens)->ordered = CIL_FALSE;
+}
+
+void cil_block_init(struct cil_block **block)
+{
+ *block = cil_malloc(sizeof(**block));
+
+ cil_symtab_datum_init(&(*block)->datum);
+
+ cil_symtab_array_init((*block)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK]);
+
+ (*block)->is_abstract = CIL_FALSE;
+
+ (*block)->bi_nodes = NULL;
+}
+
+void cil_blockinherit_init(struct cil_blockinherit **inherit)
+{
+ *inherit = cil_malloc(sizeof(**inherit));
+ (*inherit)->block_str = NULL;
+ (*inherit)->block = NULL;
+}
+
+void cil_blockabstract_init(struct cil_blockabstract **abstract)
+{
+ *abstract = cil_malloc(sizeof(**abstract));
+ (*abstract)->block_str = NULL;
+}
+
+void cil_in_init(struct cil_in **in)
+{
+ *in = cil_malloc(sizeof(**in));
+
+ cil_symtab_array_init((*in)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_IN]);
+ (*in)->block_str = NULL;
+}
+
+void cil_class_init(struct cil_class **class)
+{
+ *class = cil_malloc(sizeof(**class));
+
+ cil_symtab_datum_init(&(*class)->datum);
+
+ cil_symtab_init(&(*class)->perms, CIL_CLASS_SYM_SIZE);
+
+ (*class)->num_perms = 0;
+ (*class)->common = NULL;
+ (*class)->ordered = CIL_FALSE;
+}
+
+void cil_classorder_init(struct cil_classorder **classorder)
+{
+ *classorder = cil_malloc(sizeof(**classorder));
+
+ (*classorder)->class_list_str = NULL;
+}
+
+void cil_classcommon_init(struct cil_classcommon **classcommon)
+{
+ *classcommon = cil_malloc(sizeof(**classcommon));
+
+ (*classcommon)->class_str = NULL;
+ (*classcommon)->common_str = NULL;
+}
+
+void cil_sid_init(struct cil_sid **sid)
+{
+ *sid = cil_malloc(sizeof(**sid));
+
+ cil_symtab_datum_init(&(*sid)->datum);
+
+ (*sid)->ordered = CIL_FALSE;
+ (*sid)->context = NULL;
+}
+
+void cil_sidcontext_init(struct cil_sidcontext **sidcontext)
+{
+ *sidcontext = cil_malloc(sizeof(**sidcontext));
+
+ (*sidcontext)->sid_str = NULL;
+ (*sidcontext)->context_str = NULL;
+ (*sidcontext)->context = NULL;
+}
+
+void cil_sidorder_init(struct cil_sidorder **sidorder)
+{
+ *sidorder = cil_malloc(sizeof(**sidorder));
+
+ (*sidorder)->sid_list_str = NULL;
+}
+
+void cil_userrole_init(struct cil_userrole **userrole)
+{
+ *userrole = cil_malloc(sizeof(**userrole));
+
+ (*userrole)->user_str = NULL;
+ (*userrole)->user = NULL;
+ (*userrole)->role_str = NULL;
+ (*userrole)->role = NULL;
+}
+
+void cil_userprefix_init(struct cil_userprefix **userprefix)
+{
+ *userprefix = cil_malloc(sizeof(**userprefix));
+
+ (*userprefix)->user_str = NULL;
+ (*userprefix)->user = NULL;
+ (*userprefix)->prefix_str = NULL;
+}
+
+void cil_selinuxuser_init(struct cil_selinuxuser **selinuxuser)
+{
+ *selinuxuser = cil_malloc(sizeof(**selinuxuser));
+
+ (*selinuxuser)->name_str = NULL;
+ (*selinuxuser)->user_str = NULL;
+ (*selinuxuser)->user = NULL;
+ (*selinuxuser)->range_str = NULL;
+ (*selinuxuser)->range = NULL;
+}
+
+void cil_roletype_init(struct cil_roletype **roletype)
+{
+ *roletype = cil_malloc(sizeof(**roletype));
+
+ (*roletype)->role_str = NULL;
+ (*roletype)->role = NULL;
+ (*roletype)->type_str = NULL;
+ (*roletype)->type = NULL;
+}
+
+void cil_roleattribute_init(struct cil_roleattribute **attr)
+{
+ *attr = cil_malloc(sizeof(**attr));
+
+ cil_symtab_datum_init(&(*attr)->datum);
+
+ (*attr)->expr_list = NULL;
+ (*attr)->roles = NULL;
+}
+
+void cil_roleattributeset_init(struct cil_roleattributeset **attrset)
+{
+ *attrset = cil_malloc(sizeof(**attrset));
+
+ (*attrset)->attr_str = NULL;
+ (*attrset)->str_expr = NULL;
+ (*attrset)->datum_expr = NULL;
+}
+
+void cil_typeattribute_init(struct cil_typeattribute **attr)
+{
+ *attr = cil_malloc(sizeof(**attr));
+
+ cil_symtab_datum_init(&(*attr)->datum);
+
+ (*attr)->expr_list = NULL;
+ (*attr)->types = NULL;
+ (*attr)->used = CIL_FALSE;
+}
+
+void cil_typeattributeset_init(struct cil_typeattributeset **attrset)
+{
+ *attrset = cil_malloc(sizeof(**attrset));
+
+ (*attrset)->attr_str = NULL;
+ (*attrset)->str_expr = NULL;
+ (*attrset)->datum_expr = NULL;
+}
+
+void cil_alias_init(struct cil_alias **alias)
+{
+ *alias = cil_malloc(sizeof(**alias));
+
+ (*alias)->actual = NULL;
+
+ cil_symtab_datum_init(&(*alias)->datum);
+}
+
+void cil_aliasactual_init(struct cil_aliasactual **aliasactual)
+{
+ *aliasactual = cil_malloc(sizeof(**aliasactual));
+
+ (*aliasactual)->alias_str = NULL;
+ (*aliasactual)->actual_str = NULL;
+}
+
+void cil_typepermissive_init(struct cil_typepermissive **typeperm)
+{
+ *typeperm = cil_malloc(sizeof(**typeperm));
+
+ (*typeperm)->type_str = NULL;
+ (*typeperm)->type = NULL;
+}
+
+void cil_name_init(struct cil_name **name)
+{
+ *name = cil_malloc(sizeof(**name));
+
+ cil_symtab_datum_init(&(*name)->datum);
+ (*name)->name_str = NULL;
+}
+
+void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans)
+{
+ *nametypetrans = cil_malloc(sizeof(**nametypetrans));
+
+ (*nametypetrans)->src_str = NULL;
+ (*nametypetrans)->src = NULL;
+ (*nametypetrans)->tgt_str = NULL;
+ (*nametypetrans)->tgt = NULL;
+ (*nametypetrans)->obj_str = NULL;
+ (*nametypetrans)->obj = NULL;
+ (*nametypetrans)->name_str = NULL;
+ (*nametypetrans)->name = NULL;
+ (*nametypetrans)->result_str = NULL;
+ (*nametypetrans)->result = NULL;
+}
+
+void cil_rangetransition_init(struct cil_rangetransition **rangetrans)
+{
+ *rangetrans = cil_malloc(sizeof(**rangetrans));
+
+ (*rangetrans)->src_str = NULL;
+ (*rangetrans)->src = NULL;
+ (*rangetrans)->exec_str = NULL;
+ (*rangetrans)->exec = NULL;
+ (*rangetrans)->obj_str = NULL;
+ (*rangetrans)->obj = NULL;
+ (*rangetrans)->range_str = NULL;
+ (*rangetrans)->range = NULL;
+}
+
+void cil_bool_init(struct cil_bool **cilbool)
+{
+ *cilbool = cil_malloc(sizeof(**cilbool));
+
+ cil_symtab_datum_init(&(*cilbool)->datum);
+ (*cilbool)->value = 0;
+}
+
+void cil_tunable_init(struct cil_tunable **ciltun)
+{
+ *ciltun = cil_malloc(sizeof(**ciltun));
+
+ cil_symtab_datum_init(&(*ciltun)->datum);
+ (*ciltun)->value = 0;
+}
+
+void cil_condblock_init(struct cil_condblock **cb)
+{
+ *cb = cil_malloc(sizeof(**cb));
+
+ (*cb)->flavor = CIL_NONE;
+ cil_symtab_array_init((*cb)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_CONDBLOCK]);
+}
+
+void cil_boolif_init(struct cil_booleanif **bif)
+{
+ *bif = cil_malloc(sizeof(**bif));
+
+ (*bif)->str_expr = NULL;
+ (*bif)->datum_expr = NULL;
+}
+
+void cil_tunif_init(struct cil_tunableif **tif)
+{
+ *tif = cil_malloc(sizeof(**tif));
+
+ (*tif)->str_expr = NULL;
+ (*tif)->datum_expr = NULL;
+}
+
+void cil_avrule_init(struct cil_avrule **avrule)
+{
+ *avrule = cil_malloc(sizeof(**avrule));
+
+ (*avrule)->is_extended = 0;
+ (*avrule)->rule_kind = CIL_NONE;
+ (*avrule)->src_str = NULL;
+ (*avrule)->src = NULL;
+ (*avrule)->tgt_str = NULL;
+ (*avrule)->tgt = NULL;
+ memset(&((*avrule)->perms), 0, sizeof((*avrule)->perms));
+}
+
+void cil_permissionx_init(struct cil_permissionx **permx)
+{
+ *permx = cil_malloc(sizeof(**permx));
+
+ cil_symtab_datum_init(&(*permx)->datum);
+ (*permx)->kind = CIL_NONE;
+ (*permx)->obj_str = NULL;
+ (*permx)->obj = NULL;
+ (*permx)->expr_str = NULL;
+ (*permx)->perms = NULL;
+}
+
+void cil_type_rule_init(struct cil_type_rule **type_rule)
+{
+ *type_rule = cil_malloc(sizeof(**type_rule));
+
+ (*type_rule)->rule_kind = CIL_NONE;
+ (*type_rule)->src_str = NULL;
+ (*type_rule)->src = NULL;
+ (*type_rule)->tgt_str = NULL;
+ (*type_rule)->tgt = NULL;
+ (*type_rule)->obj_str = NULL;
+ (*type_rule)->obj = NULL;
+ (*type_rule)->result_str = NULL;
+ (*type_rule)->result = NULL;
+}
+
+void cil_roletransition_init(struct cil_roletransition **role_trans)
+{
+ *role_trans = cil_malloc(sizeof(**role_trans));
+
+ (*role_trans)->src_str = NULL;
+ (*role_trans)->src = NULL;
+ (*role_trans)->tgt_str = NULL;
+ (*role_trans)->tgt = NULL;
+ (*role_trans)->obj_str = NULL;
+ (*role_trans)->obj = NULL;
+ (*role_trans)->result_str = NULL;
+ (*role_trans)->result = NULL;
+}
+
+void cil_roleallow_init(struct cil_roleallow **roleallow)
+{
+ *roleallow = cil_malloc(sizeof(**roleallow));
+
+ (*roleallow)->src_str = NULL;
+ (*roleallow)->src = NULL;
+ (*roleallow)->tgt_str = NULL;
+ (*roleallow)->tgt = NULL;
+}
+
+void cil_catset_init(struct cil_catset **catset)
+{
+ *catset = cil_malloc(sizeof(**catset));
+
+ cil_symtab_datum_init(&(*catset)->datum);
+ (*catset)->cats = NULL;
+}
+
+void cil_senscat_init(struct cil_senscat **senscat)
+{
+ *senscat = cil_malloc(sizeof(**senscat));
+
+ (*senscat)->sens_str = NULL;
+ (*senscat)->cats = NULL;
+}
+
+void cil_cats_init(struct cil_cats **cats)
+{
+ *cats = cil_malloc(sizeof(**cats));
+
+ (*cats)->evaluated = CIL_FALSE;
+ (*cats)->str_expr = NULL;
+ (*cats)->datum_expr = NULL;
+}
+
+void cil_filecon_init(struct cil_filecon **filecon)
+{
+ *filecon = cil_malloc(sizeof(**filecon));
+
+ (*filecon)->path_str = NULL;
+ (*filecon)->type = 0;
+ (*filecon)->context_str = NULL;
+ (*filecon)->context = NULL;
+}
+
+void cil_portcon_init(struct cil_portcon **portcon)
+{
+ *portcon = cil_malloc(sizeof(**portcon));
+ (*portcon)->proto = 0;
+ (*portcon)->port_low = 0;
+ (*portcon)->port_high = 0;
+ (*portcon)->context_str = NULL;
+ (*portcon)->context = NULL;
+}
+
+void cil_nodecon_init(struct cil_nodecon **nodecon)
+{
+ *nodecon = cil_malloc(sizeof(**nodecon));
+
+ (*nodecon)->addr_str = NULL;
+ (*nodecon)->addr = NULL;
+ (*nodecon)->mask_str = NULL;
+ (*nodecon)->mask = NULL;
+ (*nodecon)->context_str = NULL;
+ (*nodecon)->context = NULL;
+}
+
+void cil_genfscon_init(struct cil_genfscon **genfscon)
+{
+ *genfscon = cil_malloc(sizeof(**genfscon));
+
+ (*genfscon)->fs_str = NULL;
+ (*genfscon)->path_str = NULL;
+ (*genfscon)->context_str = NULL;
+ (*genfscon)->context = NULL;
+}
+
+void cil_pirqcon_init(struct cil_pirqcon **pirqcon)
+{
+ *pirqcon = cil_malloc(sizeof(**pirqcon));
+
+ (*pirqcon)->pirq = 0;
+ (*pirqcon)->context_str = NULL;
+ (*pirqcon)->context = NULL;
+}
+
+void cil_iomemcon_init(struct cil_iomemcon **iomemcon)
+{
+ *iomemcon = cil_malloc(sizeof(**iomemcon));
+
+ (*iomemcon)->iomem_low = 0;
+ (*iomemcon)->iomem_high = 0;
+ (*iomemcon)->context_str = NULL;
+ (*iomemcon)->context = NULL;
+}
+
+void cil_ioportcon_init(struct cil_ioportcon **ioportcon)
+{
+ *ioportcon = cil_malloc(sizeof(**ioportcon));
+
+ (*ioportcon)->context_str = NULL;
+ (*ioportcon)->context = NULL;
+}
+
+void cil_pcidevicecon_init(struct cil_pcidevicecon **pcidevicecon)
+{
+ *pcidevicecon = cil_malloc(sizeof(**pcidevicecon));
+
+ (*pcidevicecon)->dev = 0;
+ (*pcidevicecon)->context_str = NULL;
+ (*pcidevicecon)->context = NULL;
+}
+
+void cil_devicetreecon_init(struct cil_devicetreecon **dtcon)
+{
+ *dtcon = cil_malloc(sizeof(**dtcon));
+
+ (*dtcon)->path = NULL;
+ (*dtcon)->context_str = NULL;
+ (*dtcon)->context = NULL;
+}
+
+void cil_fsuse_init(struct cil_fsuse **fsuse)
+{
+ *fsuse = cil_malloc(sizeof(**fsuse));
+
+ (*fsuse)->type = 0;
+ (*fsuse)->fs_str = NULL;
+ (*fsuse)->context_str = NULL;
+ (*fsuse)->context = NULL;
+}
+
+void cil_constrain_init(struct cil_constrain **constrain)
+{
+ *constrain = cil_malloc(sizeof(**constrain));
+
+ (*constrain)->classperms = NULL;
+ (*constrain)->str_expr = NULL;
+ (*constrain)->datum_expr = NULL;
+}
+
+void cil_validatetrans_init(struct cil_validatetrans **validtrans)
+{
+ *validtrans = cil_malloc(sizeof(**validtrans));
+
+ (*validtrans)->class_str = NULL;
+ (*validtrans)->class = NULL;
+ (*validtrans)->str_expr = NULL;
+ (*validtrans)->datum_expr = NULL;
+}
+
+void cil_ipaddr_init(struct cil_ipaddr **ipaddr)
+{
+ *ipaddr = cil_malloc(sizeof(**ipaddr));
+
+ cil_symtab_datum_init(&(*ipaddr)->datum);
+ memset(&(*ipaddr)->ip, 0, sizeof((*ipaddr)->ip));
+}
+
+void cil_perm_init(struct cil_perm **perm)
+{
+ *perm = cil_malloc(sizeof(**perm));
+
+ cil_symtab_datum_init(&(*perm)->datum);
+ (*perm)->value = 0;
+ (*perm)->classperms = NULL;
+}
+
+void cil_classpermission_init(struct cil_classpermission **cp)
+{
+ *cp = cil_malloc(sizeof(**cp));
+
+ cil_symtab_datum_init(&(*cp)->datum);
+ (*cp)->classperms = NULL;
+}
+
+void cil_classpermissionset_init(struct cil_classpermissionset **cps)
+{
+ *cps = cil_malloc(sizeof(**cps));
+
+ (*cps)->set_str = NULL;
+ (*cps)->classperms = NULL;
+}
+
+void cil_classperms_set_init(struct cil_classperms_set **cp_set)
+{
+ *cp_set = cil_malloc(sizeof(**cp_set));
+ (*cp_set)->set_str = NULL;
+ (*cp_set)->set = NULL;
+}
+
+void cil_classperms_init(struct cil_classperms **cp)
+{
+ *cp = cil_malloc(sizeof(**cp));
+ (*cp)->class_str = NULL;
+ (*cp)->class = NULL;
+ (*cp)->perm_strs = NULL;
+ (*cp)->perms = NULL;
+}
+
+void cil_classmapping_init(struct cil_classmapping **mapping)
+{
+ *mapping = cil_malloc(sizeof(**mapping));
+
+ (*mapping)->map_class_str = NULL;
+ (*mapping)->map_perm_str = NULL;
+ (*mapping)->classperms = NULL;
+}
+
+void cil_user_init(struct cil_user **user)
+{
+ *user = cil_malloc(sizeof(**user));
+
+ cil_symtab_datum_init(&(*user)->datum);
+ (*user)->bounds = NULL;
+ (*user)->roles = NULL;
+ (*user)->dftlevel = NULL;
+ (*user)->range = NULL;
+ (*user)->value = 0;
+}
+
+void cil_userattribute_init(struct cil_userattribute **attr)
+{
+ *attr = cil_malloc(sizeof(**attr));
+
+ cil_symtab_datum_init(&(*attr)->datum);
+
+ (*attr)->expr_list = NULL;
+ (*attr)->users = NULL;
+}
+
+void cil_userattributeset_init(struct cil_userattributeset **attrset)
+{
+ *attrset = cil_malloc(sizeof(**attrset));
+
+ (*attrset)->attr_str = NULL;
+ (*attrset)->str_expr = NULL;
+ (*attrset)->datum_expr = NULL;
+}
+
+void cil_userlevel_init(struct cil_userlevel **usrlvl)
+{
+ *usrlvl = cil_malloc(sizeof(**usrlvl));
+
+ (*usrlvl)->user_str = NULL;
+ (*usrlvl)->level_str = NULL;
+ (*usrlvl)->level = NULL;
+}
+
+void cil_userrange_init(struct cil_userrange **userrange)
+{
+ *userrange = cil_malloc(sizeof(**userrange));
+
+ (*userrange)->user_str = NULL;
+ (*userrange)->range_str = NULL;
+ (*userrange)->range = NULL;
+}
+
+void cil_role_init(struct cil_role **role)
+{
+ *role = cil_malloc(sizeof(**role));
+
+ cil_symtab_datum_init(&(*role)->datum);
+ (*role)->bounds = NULL;
+ (*role)->types = NULL;
+ (*role)->value = 0;
+}
+
+void cil_type_init(struct cil_type **type)
+{
+ *type = cil_malloc(sizeof(**type));
+
+ cil_symtab_datum_init(&(*type)->datum);
+ (*type)->bounds = NULL;
+ (*type)->value = 0;
+}
+
+void cil_cat_init(struct cil_cat **cat)
+{
+ *cat = cil_malloc(sizeof(**cat));
+
+ cil_symtab_datum_init(&(*cat)->datum);
+ (*cat)->ordered = CIL_FALSE;
+ (*cat)->value = 0;
+}
+
+void cil_catorder_init(struct cil_catorder **catorder)
+{
+ *catorder = cil_malloc(sizeof(**catorder));
+
+ (*catorder)->cat_list_str = NULL;
+}
+
+void cil_sensorder_init(struct cil_sensorder **sensorder)
+{
+ *sensorder = cil_malloc(sizeof(**sensorder));
+
+ (*sensorder)->sens_list_str = NULL;
+}
+
+void cil_args_init(struct cil_args **args)
+{
+ *args = cil_malloc(sizeof(**args));
+ (*args)->arg_str = NULL;
+ (*args)->arg = NULL;
+ (*args)->param_str = NULL;
+ (*args)->flavor = CIL_NONE;
+}
+
+void cil_call_init(struct cil_call **call)
+{
+ *call = cil_malloc(sizeof(**call));
+
+ (*call)->macro_str = NULL;
+ (*call)->macro = NULL;
+ (*call)->args_tree = NULL;
+ (*call)->args = NULL;
+ (*call)->copied = 0;
+}
+
+void cil_optional_init(struct cil_optional **optional)
+{
+ *optional = cil_malloc(sizeof(**optional));
+ (*optional)->enabled = CIL_TRUE;
+ cil_symtab_datum_init(&(*optional)->datum);
+}
+
+void cil_param_init(struct cil_param **param)
+{
+ *param = cil_malloc(sizeof(**param));
+
+ (*param)->str = NULL;
+ (*param)->flavor = CIL_NONE;
+}
+
+void cil_macro_init(struct cil_macro **macro)
+{
+ *macro = cil_malloc(sizeof(**macro));
+
+ cil_symtab_datum_init(&(*macro)->datum);
+ cil_symtab_array_init((*macro)->symtab, cil_sym_sizes[CIL_SYM_ARRAY_MACRO]);
+ (*macro)->params = NULL;
+}
+
+void cil_policycap_init(struct cil_policycap **policycap)
+{
+ *policycap = cil_malloc(sizeof(**policycap));
+
+ cil_symtab_datum_init(&(*policycap)->datum);
+}
+
+void cil_bounds_init(struct cil_bounds **bounds)
+{
+ *bounds = cil_malloc(sizeof(**bounds));
+
+ (*bounds)->parent_str = NULL;
+ (*bounds)->child_str = NULL;
+}
+
+void cil_default_init(struct cil_default **def)
+{
+ *def = cil_malloc(sizeof(**def));
+
+ (*def)->flavor = CIL_NONE;
+ (*def)->class_strs = NULL;
+ (*def)->class_datums = NULL;
+}
+
+void cil_defaultrange_init(struct cil_defaultrange **def)
+{
+ *def = cil_malloc(sizeof(**def));
+
+ (*def)->class_strs = NULL;
+ (*def)->class_datums = NULL;
+}
+
+void cil_handleunknown_init(struct cil_handleunknown **unk)
+{
+ *unk = cil_malloc(sizeof(**unk));
+}
+
+void cil_mls_init(struct cil_mls **mls)
+{
+ *mls = cil_malloc(sizeof(**mls));
+ (*mls)->value = 0;
+}
+
+void cil_src_info_init(struct cil_src_info **info)
+{
+ *info = cil_malloc(sizeof(**info));
+ (*info)->is_cil = 0;
+ (*info)->path = NULL;
+}
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
new file mode 100644
index 0000000..5d03127
--- /dev/null
+++ b/libsepol/cil/src/cil_binary.c
@@ -0,0 +1,4808 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/hierarchy.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_binary.h"
+#include "cil_symtab.h"
+#include "cil_find.h"
+
+/* There are 44000 filename_trans in current fedora policy. 1.33 times this is the recommended
+ * size of a hashtable. The next power of 2 of this is 2 ** 16.
+ */
+#define FILENAME_TRANS_TABLE_SIZE (1 << 16)
+#define RANGE_TRANS_TABLE_SIZE (1 << 13)
+#define ROLE_TRANS_TABLE_SIZE (1 << 10)
+#define AVRULEX_TABLE_SIZE (1 << 10)
+#define PERMS_PER_CLASS 32
+
+struct cil_args_binary {
+ const struct cil_db *db;
+ policydb_t *pdb;
+ struct cil_list *neverallows;
+ int pass;
+ hashtab_t filename_trans_table;
+ hashtab_t range_trans_table;
+ hashtab_t role_trans_table;
+ hashtab_t avrulex_ioctl_table;
+ void **type_value_to_cil;
+};
+
+struct cil_args_booleanif {
+ const struct cil_db *db;
+ policydb_t *pdb;
+ cond_node_t *cond_node;
+ enum cil_flavor cond_flavor;
+ hashtab_t filename_trans_table;
+};
+
+static int __cil_get_sepol_user_datum(policydb_t *pdb, struct cil_symtab_datum *datum, user_datum_t **sepol_user)
+{
+ *sepol_user = hashtab_search(pdb->p_users.table, datum->fqn);
+ if (*sepol_user == NULL) {
+ cil_log(CIL_INFO, "Failed to find user %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_get_sepol_role_datum(policydb_t *pdb, struct cil_symtab_datum *datum, role_datum_t **sepol_role)
+{
+ *sepol_role = hashtab_search(pdb->p_roles.table, datum->fqn);
+ if (*sepol_role == NULL) {
+ cil_log(CIL_INFO, "Failed to find role %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_get_sepol_type_datum(policydb_t *pdb, struct cil_symtab_datum *datum, type_datum_t **sepol_type)
+{
+ *sepol_type = hashtab_search(pdb->p_types.table, datum->fqn);
+ if (*sepol_type == NULL) {
+ cil_log(CIL_INFO, "Failed to find type %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_get_sepol_class_datum(policydb_t *pdb, struct cil_symtab_datum *datum, class_datum_t **sepol_class)
+{
+ *sepol_class = hashtab_search(pdb->p_classes.table, datum->fqn);
+ if (*sepol_class == NULL) {
+ cil_log(CIL_INFO, "Failed to find class %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_get_sepol_cat_datum(policydb_t *pdb, struct cil_symtab_datum *datum, cat_datum_t **sepol_cat)
+{
+ *sepol_cat = hashtab_search(pdb->p_cats.table, datum->fqn);
+ if (*sepol_cat == NULL) {
+ cil_log(CIL_INFO, "Failed to find category %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_get_sepol_level_datum(policydb_t *pdb, struct cil_symtab_datum *datum, level_datum_t **sepol_level)
+{
+ *sepol_level = hashtab_search(pdb->p_levels.table, datum->fqn);
+ if (*sepol_level == NULL) {
+ cil_log(CIL_INFO, "Failed to find level %s in sepol hashtab\n", datum->fqn);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_expand_user(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+ struct cil_tree_node *node = datum->nodes->head->data;
+ struct cil_user *user = NULL;
+ struct cil_userattribute *attr = NULL;
+
+ if (node->flavor == CIL_USERATTRIBUTE) {
+ attr = (struct cil_userattribute *)datum;
+ if (ebitmap_cpy(new, attr->users)) {
+ cil_log(CIL_ERR, "Failed to copy user bits\n");
+ goto exit;
+ }
+ } else {
+ user = (struct cil_user *)datum;
+ ebitmap_init(new);
+ if (ebitmap_set_bit(new, user->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set user bit\n");
+ ebitmap_destroy(new);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_expand_role(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ if (node->flavor == CIL_ROLEATTRIBUTE) {
+ struct cil_roleattribute *attr = (struct cil_roleattribute *)datum;
+ if (ebitmap_cpy(new, attr->roles)) {
+ cil_log(CIL_ERR, "Failed to copy role bits\n");
+ goto exit;
+ }
+ } else {
+ struct cil_role *role = (struct cil_role *)datum;
+ ebitmap_init(new);
+ if (ebitmap_set_bit(new, role->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set role bit\n");
+ ebitmap_destroy(new);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_expand_type(struct cil_symtab_datum *datum, ebitmap_t *new)
+{
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ if (node->flavor == CIL_TYPEATTRIBUTE) {
+ struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+ if (ebitmap_cpy(new, attr->types)) {
+ cil_log(CIL_ERR, "Failed to copy type bits\n");
+ goto exit;
+ }
+ } else {
+ struct cil_type *type = (struct cil_type *)datum;
+ ebitmap_init(new);
+ if (ebitmap_set_bit(new, type->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set type bit\n");
+ ebitmap_destroy(new);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static ocontext_t *cil_add_ocontext(ocontext_t **head, ocontext_t **tail)
+{
+ ocontext_t *new = cil_malloc(sizeof(ocontext_t));
+ memset(new, 0, sizeof(ocontext_t));
+ if (*tail) {
+ (*tail)->next = new;
+ } else {
+ *head = new;
+ }
+ *tail = new;
+
+ return new;
+}
+
+int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ struct cil_tree_node *node = cil_common->datum.nodes->head->data;
+ struct cil_tree_node *cil_perm = node->cl_head;
+ common_datum_t *sepol_common = cil_malloc(sizeof(*sepol_common));
+ memset(sepol_common, 0, sizeof(common_datum_t));
+
+ key = cil_strdup(cil_common->datum.fqn);
+ rc = symtab_insert(pdb, SYM_COMMONS, key, sepol_common, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ free(sepol_common);
+ goto exit;
+ }
+ sepol_common->s.value = value;
+
+ rc = symtab_init(&sepol_common->permissions, PERM_SYMTAB_SIZE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ while (cil_perm != NULL) {
+ struct cil_perm *curr = cil_perm->data;
+ perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm));
+ memset(sepol_perm, 0, sizeof(perm_datum_t));
+
+ key = cil_strdup(curr->datum.fqn);
+ rc = hashtab_insert(sepol_common->permissions.table, key, sepol_perm);
+ if (rc != SEPOL_OK) {
+ free(sepol_perm);
+ goto exit;
+ }
+ sepol_perm->s.value = sepol_common->permissions.nprim + 1;
+ sepol_common->permissions.nprim++;
+ cil_perm = cil_perm->next;
+ }
+
+ *common_out = sepol_common;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ return rc;
+}
+
+int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr_class;
+
+ cil_list_for_each(curr_class, db->classorder) {
+ struct cil_class *cil_class = curr_class->data;
+ uint32_t value = 0;
+ char *key = NULL;
+ int class_index;
+ struct cil_tree_node *curr;
+ common_datum_t *sepol_common = NULL;
+ class_datum_t *sepol_class = cil_malloc(sizeof(*sepol_class));
+ memset(sepol_class, 0, sizeof(class_datum_t));
+
+ key = cil_strdup(cil_class->datum.fqn);
+ rc = symtab_insert(pdb, SYM_CLASSES, key, sepol_class, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ free(sepol_class);
+ free(key);
+ goto exit;
+ }
+ sepol_class->s.value = value;
+ class_index = value;
+ class_value_to_cil[class_index] = cil_class;
+
+ rc = symtab_init(&sepol_class->permissions, PERM_SYMTAB_SIZE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (cil_class->common != NULL) {
+ int i;
+ struct cil_class *cil_common = cil_class->common;
+
+ key = cil_class->common->datum.fqn;
+ sepol_common = hashtab_search(pdb->p_commons.table, key);
+ if (sepol_common == NULL) {
+ rc = cil_common_to_policydb(pdb, cil_common, &sepol_common);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ sepol_class->comdatum = sepol_common;
+ sepol_class->comkey = cil_strdup(key);
+ sepol_class->permissions.nprim += sepol_common->permissions.nprim;
+
+ for (curr = NODE(cil_class->common)->cl_head, i = 1; curr; curr = curr->next, i++) {
+ struct cil_perm *cil_perm = curr->data;
+ perm_value_to_cil[class_index][i] = cil_perm;
+ }
+ }
+
+ for (curr = NODE(cil_class)->cl_head; curr; curr = curr->next) {
+ struct cil_perm *cil_perm = curr->data;
+ perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm));
+ memset(sepol_perm, 0, sizeof(perm_datum_t));
+
+ key = cil_strdup(cil_perm->datum.fqn);
+ rc = hashtab_insert(sepol_class->permissions.table, key, sepol_perm);
+ if (rc != SEPOL_OK) {
+ free(sepol_perm);
+ free(key);
+ goto exit;
+ }
+ sepol_perm->s.value = sepol_class->permissions.nprim + 1;
+ sepol_class->permissions.nprim++;
+ perm_value_to_cil[class_index][sepol_perm->s.value] = cil_perm;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ role_datum_t *sepol_role = cil_malloc(sizeof(*sepol_role));
+ role_datum_init(sepol_role);
+
+ if (cil_role->datum.fqn == CIL_KEY_OBJECT_R) {
+ /* special case
+ * object_r defaults to 1 in libsepol symtab */
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ key = cil_strdup(cil_role->datum.fqn);
+ rc = symtab_insert(pdb, SYM_ROLES, (hashtab_key_t)key, sepol_role, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ if (ebitmap_set_bit(&sepol_role->dominates, value - 1, 1)) {
+ cil_log(CIL_INFO, "Failed to set dominates bit for role\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ sepol_role->s.value = value;
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ role_datum_destroy(sepol_role);
+ free(sepol_role);
+ return rc;
+}
+
+int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role)
+{
+ int rc = SEPOL_ERR;
+ role_datum_t *sepol_role = NULL;
+ role_datum_t *sepol_parent = NULL;
+
+ if (cil_role->bounds) {
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role), &sepol_role);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role->bounds), &sepol_parent);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_role->bounds = sepol_parent->s.value;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to insert role bounds for role %s\n", cil_role->datum.fqn);
+ return SEPOL_ERR;
+}
+
+int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role)
+{
+ int rc = SEPOL_ERR;
+
+ if (role->types) {
+ role_datum_t *sepol_role = NULL;
+ type_datum_t *sepol_type = NULL;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(role), &sepol_role);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(role->types, tnode, i) {
+ if (!ebitmap_get_bit(role->types, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (ebitmap_set_bit(&sepol_role->types.types, sepol_type->s.value - 1, 1)) {
+ cil_log(CIL_INFO, "Failed to set type bit for role\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[])
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ type_datum_t *sepol_type = cil_malloc(sizeof(*sepol_type));
+ type_datum_init(sepol_type);
+
+ sepol_type->flavor = TYPE_TYPE;
+
+ key = cil_strdup(cil_type->datum.fqn);
+ rc = symtab_insert(pdb, SYM_TYPES, key, sepol_type, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_type->s.value = value;
+ sepol_type->primary = 1;
+
+ type_value_to_cil[value] = cil_type;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ type_datum_destroy(sepol_type);
+ free(sepol_type);
+ return rc;
+}
+
+int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_type = NULL;
+ type_datum_t *sepol_parent = NULL;
+
+ if (cil_type->bounds) {
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type->bounds), &sepol_parent);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_type->bounds = sepol_parent->s.value;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to insert type bounds for type %s\n", cil_type->datum.fqn);
+ return SEPOL_ERR;
+}
+
+int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ type_datum_t *sepol_type = NULL;
+ type_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias));
+ type_datum_init(sepol_alias);
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_alias->actual), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_alias->flavor = TYPE_TYPE;
+
+ key = cil_strdup(cil_alias->datum.fqn);
+ rc = symtab_insert(pdb, SYM_TYPES, key, sepol_alias, SCOPE_DECL, 0, NULL);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_alias->s.value = sepol_type->s.value;
+ sepol_alias->primary = 0;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ type_datum_destroy(sepol_alias);
+ free(sepol_alias);
+ return rc;
+}
+
+int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_type = NULL;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_typeperm->type), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (ebitmap_set_bit(&pdb->permissive_map, sepol_type->s.value, 1)) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ type_datum_destroy(sepol_type);
+ free(sepol_type);
+ return rc;
+
+}
+
+int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[])
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ type_datum_t *sepol_attr = NULL;
+
+ if (cil_attr->used == CIL_FALSE) {
+ return SEPOL_OK;
+ }
+
+ sepol_attr = cil_malloc(sizeof(*sepol_attr));
+ type_datum_init(sepol_attr);
+
+ sepol_attr->flavor = TYPE_ATTRIB;
+
+ key = cil_strdup(cil_attr->datum.fqn);
+ rc = symtab_insert(pdb, SYM_TYPES, key, sepol_attr, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_attr->s.value = value;
+ sepol_attr->primary = 1;
+
+ type_value_to_cil[value] = cil_attr;
+
+ return SEPOL_OK;
+
+exit:
+ type_datum_destroy(sepol_attr);
+ free(sepol_attr);
+ return rc;
+}
+
+int __cil_typeattr_bitmap_init(policydb_t *pdb)
+{
+ int rc = SEPOL_ERR;
+
+ pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t));
+ pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t));
+
+ uint32_t i = 0;
+ for (i = 0; i < pdb->p_types.nprim; i++) {
+ ebitmap_init(&pdb->type_attr_map[i]);
+ ebitmap_init(&pdb->attr_type_map[i]);
+ if (ebitmap_set_bit(&pdb->type_attr_map[i], i, 1)) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ if (pdb->type_val_to_struct[i] && pdb->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
+ if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *db, struct cil_typeattribute *cil_attr)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ type_datum_t *sepol_type = NULL;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ if (cil_attr->used == CIL_FALSE) {
+ return SEPOL_OK;
+ }
+
+ if (pdb->type_attr_map == NULL) {
+ rc = __cil_typeattr_bitmap_init(pdb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_attr), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ value = sepol_type->s.value;
+
+ ebitmap_for_each_bit(cil_attr->types, tnode, i) {
+ if (!ebitmap_get_bit(cil_attr->types, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_set_bit(&pdb->type_attr_map[sepol_type->s.value - 1], value - 1, 1);
+ ebitmap_set_bit(&pdb->attr_type_map[value - 1], sepol_type->s.value - 1, 1);
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+}
+
+int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap)
+{
+ int rc = SEPOL_ERR;
+ int capnum;
+
+ capnum = sepol_polcap_getnum(cil_polcap->datum.fqn);
+ if (capnum == -1) {
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&pdb->policycaps, capnum, 1)) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ user_datum_t *sepol_user = cil_malloc(sizeof(*sepol_user));
+ user_datum_init(sepol_user);
+
+ key = cil_strdup(cil_user->datum.fqn);
+ rc = symtab_insert(pdb, SYM_USERS, key, sepol_user, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_user->s.value = value;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ user_datum_destroy(sepol_user);
+ free(sepol_user);
+ return rc;
+}
+
+int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+ int rc = SEPOL_ERR;
+ user_datum_t *sepol_user = NULL;
+ user_datum_t *sepol_parent = NULL;
+
+ if (cil_user->bounds) {
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user->bounds), &sepol_parent);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_user->bounds = sepol_parent->s.value;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to insert user bounds for user %s\n", cil_user->datum.fqn);
+ return SEPOL_ERR;
+}
+
+int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user)
+{
+ int rc = SEPOL_ERR;
+ user_datum_t *sepol_user = NULL;
+ role_datum_t *sepol_role = NULL;
+ ebitmap_node_t *rnode = NULL;
+ unsigned int i;
+
+ if (user->roles) {
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(user), &sepol_user);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ebitmap_for_each_bit(user->roles, rnode, i) {
+ if (!ebitmap_get_bit(user->roles, i)) {
+ continue;
+ }
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&sepol_user->roles.roles, sepol_role->s.value - 1, 1)) {
+ cil_log(CIL_INFO, "Failed to set role bit for user\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ cond_bool_datum_t *sepol_bool = cil_malloc(sizeof(*sepol_bool));
+ memset(sepol_bool, 0, sizeof(cond_bool_datum_t));
+
+ key = cil_strdup(cil_bool->datum.fqn);
+ rc = symtab_insert(pdb, SYM_BOOLS, key, sepol_bool, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_bool->s.value = value;
+ sepol_bool->state = cil_bool->value;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ free(sepol_bool);
+ return rc;
+}
+
+int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ struct cil_list_item *curr_cat;
+ struct cil_cat *cil_cat = NULL;
+ cat_datum_t *sepol_cat = NULL;
+
+ cil_list_for_each(curr_cat, db->catorder) {
+ cil_cat = curr_cat->data;
+ sepol_cat = cil_malloc(sizeof(*sepol_cat));
+ cat_datum_init(sepol_cat);
+
+ key = cil_strdup(cil_cat->datum.fqn);
+ rc = symtab_insert(pdb, SYM_CATS, key, sepol_cat, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_cat->s.value = value;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ cat_datum_destroy(sepol_cat);
+ free(sepol_cat);
+ return rc;
+}
+
+int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ cat_datum_t *sepol_cat;
+ cat_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_cat));
+ cat_datum_init(sepol_alias);
+
+ rc = __cil_get_sepol_cat_datum(pdb, DATUM(cil_alias->actual), &sepol_cat);
+ if (rc != SEPOL_OK) goto exit;
+
+ key = cil_strdup(cil_alias->datum.fqn);
+ rc = symtab_insert(pdb, SYM_CATS, key, sepol_alias, SCOPE_DECL, 0, NULL);
+ if (rc != SEPOL_OK) {
+ free(key);
+ goto exit;
+ }
+ sepol_alias->s.value = sepol_cat->s.value;
+ sepol_alias->isalias = 1;
+
+ return SEPOL_OK;
+
+exit:
+ free(key);
+ cat_datum_destroy(sepol_alias);
+ free(sepol_alias);
+ return rc;
+}
+
+int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ uint32_t value = 0;
+ char *key = NULL;
+ struct cil_list_item *curr;
+ struct cil_sens *cil_sens = NULL;
+ level_datum_t *sepol_level = NULL;
+ mls_level_t *mls_level = NULL;
+
+ cil_list_for_each(curr, db->sensitivityorder) {
+ cil_sens = curr->data;
+ sepol_level = cil_malloc(sizeof(*sepol_level));
+ mls_level = cil_malloc(sizeof(*mls_level));
+ level_datum_init(sepol_level);
+ mls_level_init(mls_level);
+
+ key = cil_strdup(cil_sens->datum.fqn);
+ rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_level, SCOPE_DECL, 0, &value);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ mls_level->sens = value;
+ sepol_level->level = mls_level;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ level_datum_destroy(sepol_level);
+ mls_level_destroy(mls_level);
+ free(sepol_level);
+ free(mls_level);
+ free(key);
+ return rc;
+}
+
+int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ mls_level_t *mls_level = NULL;
+ level_datum_t *sepol_level = NULL;
+ level_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias));
+ level_datum_init(sepol_alias);
+
+ rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_alias->actual), &sepol_level);
+ if (rc != SEPOL_OK) goto exit;
+
+ key = cil_strdup(cil_alias->datum.fqn);
+ rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_alias, SCOPE_DECL, 0, NULL);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ mls_level = cil_malloc(sizeof(*mls_level));
+ mls_level_init(mls_level);
+
+ rc = mls_level_cpy(mls_level, sepol_level->level);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sepol_alias->level = mls_level;
+ sepol_alias->defined = 1;
+ sepol_alias->isalias = 1;
+
+ return SEPOL_OK;
+
+exit:
+ level_datum_destroy(sepol_alias);
+ free(sepol_level);
+ free(key);
+ return rc;
+}
+
+int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_OK;
+ avtab_ptr_t avtab_ptr = NULL;
+ cond_av_list_t *cond_list = NULL;
+
+ avtab_ptr = avtab_insert_nonunique(avtab, avtab_key, avtab_datum);
+ if (!avtab_ptr) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ // parse_context needs to be non-NULL for conditional rules to be
+ // written to the binary. it is normally used for finding duplicates,
+ // but cil checks that earlier, so we don't use it. it just needs to be
+ // set
+ avtab_ptr->parse_context = (void*)1;
+
+ cond_list = cil_malloc(sizeof(cond_av_list_t));
+ memset(cond_list, 0, sizeof(cond_av_list_t));
+
+ cond_list->node = avtab_ptr;
+
+ if (cond_flavor == CIL_CONDTRUE) {
+ cond_list->next = cond_node->true_list;
+ cond_node->true_list = cond_list;
+ } else {
+ cond_list->next = cond_node->false_list;
+ cond_node->false_list = cond_list;
+ }
+
+exit:
+ return rc;
+}
+
+avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list)
+{
+ cond_av_list_t *cur_av;
+
+ for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
+ if (cur_av->node->key.source_type == key->source_type &&
+ cur_av->node->key.target_type == key->target_type &&
+ cur_av->node->key.target_class == key->target_class &&
+ (cur_av->node->key.specified & key->specified))
+
+ return &cur_av->node->datum;
+
+ }
+ return NULL;
+}
+
+int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_OK;
+ avtab_key_t avtab_key;
+ avtab_datum_t avtab_datum;
+ avtab_ptr_t existing;
+
+ avtab_key.source_type = src;
+ avtab_key.target_type = tgt;
+ avtab_key.target_class = obj;
+
+ switch (kind) {
+ case CIL_TYPE_TRANSITION:
+ avtab_key.specified = AVTAB_TRANSITION;
+ break;
+ case CIL_TYPE_CHANGE:
+ avtab_key.specified = AVTAB_CHANGE;
+ break;
+ case CIL_TYPE_MEMBER:
+ avtab_key.specified = AVTAB_MEMBER;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ avtab_datum.data = res;
+
+ existing = avtab_search_node(&pdb->te_avtab, &avtab_key);
+ if (existing) {
+ /* Don't add duplicate type rule and warn if they conflict.
+ * A warning should have been previously given if there is a
+ * non-duplicate rule using the same key.
+ */
+ if (existing->datum.data != res) {
+ cil_log(CIL_ERR, "Conflicting type rules\n");
+ rc = SEPOL_ERR;
+ }
+ goto exit;
+ }
+
+ if (!cond_node) {
+ rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum);
+ } else {
+ existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key);
+ if (existing) {
+ cond_av_list_t *this_list;
+ cond_av_list_t *other_list;
+ avtab_datum_t *search_datum;
+
+ if (cond_flavor == CIL_CONDTRUE) {
+ this_list = cond_node->true_list;
+ other_list = cond_node->false_list;
+ } else {
+ this_list = cond_node->false_list;
+ other_list = cond_node->true_list;
+ }
+
+ search_datum = cil_cond_av_list_search(&avtab_key, other_list);
+ if (search_datum == NULL) {
+ if (existing->datum.data != res) {
+ cil_log(CIL_ERR, "Conflicting type rules\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ search_datum = cil_cond_av_list_search(&avtab_key, this_list);
+ if (search_datum) {
+ goto exit;
+ }
+ }
+ }
+ rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor);
+ }
+
+exit:
+ return rc;
+}
+
+int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_ERR;
+ uint16_t kind = cil_rule->rule_kind;
+ type_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_obj = NULL;
+ struct cil_list *class_list;
+ type_datum_t *sepol_result = NULL;
+ ebitmap_t src_bitmap, tgt_bitmap;
+ ebitmap_node_t *node1, *node2;
+ unsigned int i, j;
+ struct cil_list_item *c;
+
+ rc = __cil_expand_type(cil_rule->src, &src_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_expand_type(cil_rule->tgt, &tgt_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ class_list = cil_expand_class(cil_rule->obj);
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_rule->result), &sepol_result);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&src_bitmap, node1, i) {
+ if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+ if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ cil_list_for_each(c, class_list) {
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_insert_type_rule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, sepol_result->s.value, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&src_bitmap);
+ ebitmap_destroy(&tgt_bitmap);
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return rc;
+}
+
+int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule)
+{
+ return __cil_type_rule_to_avtab(pdb, db, cil_rule, NULL, CIL_FALSE);
+}
+
+int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor, hashtab_t filename_trans_table)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_obj = NULL;
+ struct cil_list *class_list;
+ type_datum_t *sepol_result = NULL;
+ filename_trans_t *new = NULL;
+ ebitmap_t src_bitmap, tgt_bitmap;
+ ebitmap_node_t *node1, *node2;
+ unsigned int i, j;
+ struct cil_list_item *c;
+ char *name = DATUM(typetrans->name)->name;
+ uint32_t *otype = NULL;
+
+ if (name == CIL_KEY_STAR) {
+ struct cil_type_rule trans;
+ trans.rule_kind = CIL_TYPE_TRANSITION;
+ trans.src = typetrans->src;
+ trans.tgt = typetrans->tgt;
+ trans.obj = typetrans->obj;
+ trans.result = typetrans->result;
+ return __cil_type_rule_to_avtab(pdb, db, &trans, cond_node, cond_flavor);
+ }
+
+ rc = __cil_expand_type(typetrans->src, &src_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_expand_type(typetrans->tgt, &tgt_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ class_list = cil_expand_class(typetrans->obj);
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(typetrans->result), &sepol_result);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&src_bitmap, node1, i) {
+ if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+ if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ cil_list_for_each(c, class_list) {
+ int add = CIL_TRUE;
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+ if (rc != SEPOL_OK) goto exit;
+
+ new = cil_malloc(sizeof(*new));
+ memset(new, 0, sizeof(*new));
+ new->stype = sepol_src->s.value;
+ new->ttype = sepol_tgt->s.value;
+ new->tclass = sepol_obj->s.value;
+ new->otype = sepol_result->s.value;
+ new->name = cil_strdup(name);
+
+ rc = hashtab_insert(filename_trans_table, (hashtab_key_t)new, &(new->otype));
+ if (rc != SEPOL_OK) {
+ if (rc == SEPOL_EEXIST) {
+ add = CIL_FALSE;
+ otype = hashtab_search(filename_trans_table, (hashtab_key_t)new);
+ if (new->otype != *otype) {
+ cil_log(CIL_ERR, "Conflicting name type transition rules\n");
+ } else {
+ rc = SEPOL_OK;
+ }
+ } else {
+ cil_log(CIL_ERR, "Out of memory\n");
+ }
+ }
+
+ if (add == CIL_TRUE) {
+ new->next = pdb->filename_trans;
+ pdb->filename_trans = new;
+ } else {
+ free(new->name);
+ free(new);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&src_bitmap);
+ ebitmap_destroy(&tgt_bitmap);
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return rc;
+}
+
+int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, hashtab_t filename_trans_table)
+{
+ return __cil_typetransition_to_avtab(pdb, db, typetrans, NULL, CIL_FALSE, filename_trans_table);
+}
+
+int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum)
+{
+ int rc;
+ perm_datum_t *sepol_perm;
+ common_datum_t *sepol_common;
+
+ sepol_perm = hashtab_search(sepol_class->permissions.table, perm_str);
+ if (sepol_perm == NULL) {
+ sepol_common = sepol_class->comdatum;
+ sepol_perm = hashtab_search(sepol_common->permissions.table, perm_str);
+ if (sepol_perm == NULL) {
+ cil_log(CIL_ERR, "Failed to find datum for perm %s\n", perm_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ *datum |= 1 << (sepol_perm->s.value - 1);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ struct cil_list_item *curr_perm;
+ struct cil_perm *cil_perm;
+ uint32_t data = 0;
+
+ cil_list_for_each(curr_perm, perms) {
+ cil_perm = curr_perm->data;
+ key = cil_perm->datum.fqn;
+
+ rc = __perm_str_to_datum(key, sepol_class, &data);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ *datum = data;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_OK;
+ avtab_key_t avtab_key;
+ avtab_datum_t avtab_datum;
+ avtab_datum_t *avtab_dup = NULL;
+
+ avtab_key.source_type = src;
+ avtab_key.target_type = tgt;
+ avtab_key.target_class = obj;
+
+ switch (kind) {
+ case CIL_AVRULE_ALLOWED:
+ avtab_key.specified = AVTAB_ALLOWED;
+ break;
+ case CIL_AVRULE_AUDITALLOW:
+ avtab_key.specified = AVTAB_AUDITALLOW;
+ break;
+ case CIL_AVRULE_DONTAUDIT:
+ avtab_key.specified = AVTAB_AUDITDENY;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ break;
+ }
+
+ if (!cond_node) {
+ avtab_dup = avtab_search(&pdb->te_avtab, &avtab_key);
+ if (!avtab_dup) {
+ avtab_datum.data = data;
+ rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum);
+ } else {
+ if (kind == CIL_AVRULE_DONTAUDIT)
+ avtab_dup->data &= data;
+ else
+ avtab_dup->data |= data;
+ }
+ } else {
+ avtab_datum.data = data;
+ rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor);
+ }
+
+exit:
+ return rc;
+}
+
+int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_class = NULL;
+ uint32_t data = 0;
+
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_perms_to_datum(cp->perms, sepol_class, &data);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (data == 0) {
+ /* No permissions, so don't insert rule. Maybe should return an error? */
+ return SEPOL_OK;
+ }
+
+ if (kind == CIL_AVRULE_DONTAUDIT) {
+ data = ~data;
+ }
+
+ rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_insert_avrule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_class->s.value, data, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ rc = __cil_avrule_expand_helper(pdb, kind, src, tgt, cp, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ rc = __cil_avrule_expand(pdb, kind, src, tgt, cmp->classperms, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = __cil_avrule_expand(pdb, kind, src, tgt, cp->classperms, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor)
+{
+ int rc = SEPOL_ERR;
+ uint16_t kind = cil_avrule->rule_kind;
+ struct cil_symtab_datum *src = NULL;
+ struct cil_symtab_datum *tgt = NULL;
+ struct cil_list *classperms = cil_avrule->perms.classperms;
+
+ if (cil_avrule->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) {
+ // Do not add dontaudit rules to binary
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ src = cil_avrule->src;
+ tgt = cil_avrule->tgt;
+
+ if (tgt->fqn == CIL_KEY_SELF) {
+ ebitmap_t type_bitmap;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ rc = __cil_expand_type(src, &type_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+ if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+ src = DATUM(db->val_to_type[i]);
+ rc = __cil_avrule_expand(pdb, kind, src, src, classperms, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&type_bitmap);
+ goto exit;
+ }
+ }
+ ebitmap_destroy(&type_bitmap);
+ } else {
+ rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule)
+{
+ return __cil_avrule_to_avtab(pdb, db, cil_avrule, NULL, CIL_FALSE);
+}
+
+// Copied from checkpolicy/policy_define.c
+
+/* index of the u32 containing the permission */
+#define XPERM_IDX(x) (x >> 5)
+/* set bits 0 through x-1 within the u32 */
+#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
+/* low value for this u32 */
+#define XPERM_LOW(x) (x << 5)
+/* high value for this u32 */
+#define XPERM_HIGH(x) (((x + 1) << 5) - 1)
+void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_extended_perms *xperms)
+{
+ unsigned int i;
+ uint16_t h = high + 1;
+ /* for each u32 that this low-high range touches, set driver permissions */
+ for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) {
+ /* set all bits in u32 */
+ if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+ xperms->perms[i] |= ~0U;
+ /* set low bits */
+ else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i)))
+ xperms->perms[i] |= XPERM_SETBITS(h);
+ /* set high bits */
+ else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+ xperms->perms[i] |= ~0U - XPERM_SETBITS(low);
+ /* set middle bits */
+ else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i)))
+ xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
+ }
+}
+
+
+#define IOC_DRIV(x) (x >> 8)
+#define IOC_FUNC(x) (x & 0xff)
+
+int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list)
+{
+ ebitmap_node_t *node;
+ unsigned int i;
+ uint16_t low = 0, high = 0;
+ struct avtab_extended_perms *partial = NULL;
+ struct avtab_extended_perms *complete = NULL;
+ int start_new_range;
+
+ cil_list_init(xperms_list, CIL_NONE);
+
+ start_new_range = 1;
+
+ ebitmap_for_each_bit(xperms, node, i) {
+ if (!ebitmap_get_bit(xperms, i)) continue;
+
+ if (start_new_range) {
+ low = i;
+ start_new_range = 0;
+ }
+
+ // continue if the current bit isn't the end of the driver function or the next bit is set
+ if (IOC_FUNC(i) != 0xff && ebitmap_get_bit(xperms, i + 1)) {
+ continue;
+ }
+
+ // if we got here, i is the end of this range (either becuase the func
+ // is 0xff or the next bit isn't set). The next time around we are
+ // going to need a start a new range
+ high = i;
+ start_new_range = 1;
+
+ if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) {
+ if (!complete) {
+ complete = cil_calloc(1, sizeof(*complete));
+ complete->driver = 0x0;
+ complete->specified = AVTAB_XPERMS_IOCTLDRIVER;
+ }
+
+ __avrule_xperm_setrangebits(IOC_DRIV(low), IOC_DRIV(low), complete);
+ } else {
+ if (partial && partial->driver != IOC_DRIV(low)) {
+ cil_list_append(*xperms_list, CIL_NONE, partial);
+ partial = NULL;
+ }
+
+ if (!partial) {
+ partial = cil_calloc(1, sizeof(*partial));
+ partial->driver = IOC_DRIV(low);
+ partial->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+ }
+
+ __avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial);
+ }
+ }
+
+ if (partial) {
+ cil_list_append(*xperms_list, CIL_NONE, partial);
+ }
+
+ if (complete) {
+ cil_list_append(*xperms_list, CIL_NONE, complete);
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args)
+{
+ int rc = SEPOL_OK;
+ struct policydb *pdb;
+ avtab_key_t *avtab_key;
+ avtab_datum_t avtab_datum;
+ struct cil_list *xperms_list = NULL;
+ struct cil_list_item *item;
+ class_datum_t *sepol_obj;
+ uint32_t data = 0;
+
+ avtab_key = (avtab_key_t *)k;
+ pdb = args;
+
+ sepol_obj = pdb->class_val_to_struct[avtab_key->target_class - 1];
+
+ // setting the data for an extended avtab isn't really neccessary because
+ // it is ignored by the kernel. However, neverallow checking requires that
+ // the data value be set, so set it for that to work.
+ rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ avtab_datum.data = data;
+
+ rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_for_each(item, xperms_list) {
+ avtab_datum.xperms = item->data;
+ rc = avtab_insert(&pdb->te_avtab, avtab_key, &avtab_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ if (xperms_list != NULL) {
+ cil_list_for_each(item, xperms_list) {
+ free(item->data);
+ }
+ cil_list_destroy(&xperms_list, CIL_FALSE);
+ }
+
+ // hashtab_t does not have a way to free keys or datum since it doesn't
+ // know what they are. We won't need the keys/datum after this function, so
+ // clean them up here.
+ free(avtab_key);
+ ebitmap_destroy(datum);
+ free(datum);
+
+ return rc;
+}
+
+int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms)
+{
+ uint16_t specified;
+ avtab_key_t *avtab_key;
+ ebitmap_t *hashtab_xperms;
+ int rc = SEPOL_ERR;
+
+ switch (kind) {
+ case CIL_AVRULE_ALLOWED:
+ specified = AVTAB_XPERMS_ALLOWED;
+ break;
+ case CIL_AVRULE_AUDITALLOW:
+ specified = AVTAB_XPERMS_AUDITALLOW;
+ break;
+ case CIL_AVRULE_DONTAUDIT:
+ specified = AVTAB_XPERMS_DONTAUDIT;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ avtab_key = cil_malloc(sizeof(*avtab_key));
+ avtab_key->source_type = src;
+ avtab_key->target_type = tgt;
+ avtab_key->target_class = obj;
+ avtab_key->specified = specified;
+
+ hashtab_xperms = (ebitmap_t *)hashtab_search(h, (hashtab_key_t)avtab_key);
+ if (!hashtab_xperms) {
+ hashtab_xperms = cil_malloc(sizeof(*hashtab_xperms));
+ rc = ebitmap_cpy(hashtab_xperms, xperms);
+ if (rc != SEPOL_OK) {
+ free(avtab_key);
+ goto exit;
+ }
+ rc = hashtab_insert(h, (hashtab_key_t)avtab_key, hashtab_xperms);
+ if (rc != SEPOL_OK) {
+ free(avtab_key);
+ goto exit;
+ }
+ } else {
+ free(avtab_key);
+ rc = ebitmap_union(hashtab_xperms, xperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_obj = NULL;
+ struct cil_list *class_list = NULL;
+ struct cil_list_item *c;
+
+ rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ class_list = cil_expand_class(permx->obj);
+
+ cil_list_for_each(c, class_list) {
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+ if (rc != SEPOL_OK) goto exit;
+
+ switch (permx->kind) {
+ case CIL_PERMX_KIND_IOCTL:
+ rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms);
+ if (rc != SEPOL_OK) goto exit;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ cil_list_destroy(&class_list, CIL_FALSE);
+
+ return rc;
+}
+
+int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args)
+{
+ int rc = SEPOL_ERR;
+ uint16_t kind;
+ struct cil_symtab_datum *src = NULL;
+ struct cil_symtab_datum *tgt = NULL;
+ ebitmap_t type_bitmap;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ ebitmap_init(&type_bitmap);
+
+ if (cil_avrulex->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) {
+ // Do not add dontaudit rules to binary
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ kind = cil_avrulex->rule_kind;
+ src = cil_avrulex->src;
+ tgt = cil_avrulex->tgt;
+
+ if (tgt->fqn == CIL_KEY_SELF) {
+ rc = __cil_expand_type(src, &type_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+ if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+ src = DATUM(db->val_to_type[i]);
+ rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, src, cil_avrulex->perms.x.permx, args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args);
+ if (rc != SEPOL_OK) goto exit;
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&type_bitmap);
+
+ return rc;
+}
+
+int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+ int rc;
+ enum cil_flavor flavor;
+ struct cil_args_booleanif *args = extra_args;
+ const struct cil_db *db = args->db;
+ policydb_t *pdb = args->pdb;
+ cond_node_t *cond_node = args->cond_node;
+ enum cil_flavor cond_flavor = args->cond_flavor;
+ struct cil_type_rule *cil_type_rule;
+ struct cil_avrule *cil_avrule;
+ struct cil_nametypetransition *cil_typetrans;
+ hashtab_t filename_trans_table = args->filename_trans_table;
+
+ flavor = node->flavor;
+ switch (flavor) {
+ case CIL_NAMETYPETRANSITION:
+ cil_typetrans = (struct cil_nametypetransition*)node->data;
+ if (DATUM(cil_typetrans->name)->fqn != CIL_KEY_STAR) {
+ cil_log(CIL_ERR, "typetransition with file name not allowed within a booleanif block.\n");
+ cil_tree_log(node, CIL_ERR,"Invalid typetransition statement");
+ goto exit;
+ }
+ rc = __cil_typetransition_to_avtab(pdb, db, cil_typetrans, cond_node, cond_flavor, filename_trans_table);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Failed to insert type transition into avtab");
+ goto exit;
+ }
+ break;
+ case CIL_TYPE_RULE:
+ cil_type_rule = node->data;
+ rc = __cil_type_rule_to_avtab(pdb, db, cil_type_rule, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Failed to insert typerule into avtab");
+ goto exit;
+ }
+ break;
+ case CIL_AVRULE:
+ cil_avrule = node->data;
+ rc = __cil_avrule_to_avtab(pdb, db, cil_avrule, cond_node, cond_flavor);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Failed to insert avrule into avtab");
+ goto exit;
+ }
+ break;
+ case CIL_CALL:
+ case CIL_TUNABLEIF:
+ break;
+ default:
+ cil_tree_log(node, CIL_ERR, "Invalid statement within booleanif");
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out);
+
+static void __cil_expr_to_string_helper(struct cil_list_item *curr, enum cil_flavor flavor, char **out)
+{
+ char *c;
+
+ if (curr->flavor == CIL_DATUM) {
+ *out = cil_strdup(DATUM(curr->data)->fqn);
+ } else if (curr->flavor == CIL_LIST) {
+ __cil_expr_to_string(curr->data, flavor, &c);
+ cil_asprintf(out, "(%s)", c);
+ free(c);
+ } else if (flavor == CIL_PERMISSIONX) {
+ // permissionx expressions aren't resolved into anything, so curr->flavor
+ // is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those
+ *out = cil_strdup(curr->data);
+ }
+}
+
+static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out)
+{
+ struct cil_list_item *curr;
+ char *s1 = NULL;
+ char *s2 = NULL;
+ enum cil_flavor op;
+
+ if (expr == NULL || expr->head == NULL) {
+ *out = cil_strdup("");
+ return;
+ }
+
+ curr = expr->head;
+
+ if (curr->flavor == CIL_OP) {
+ op = (enum cil_flavor)curr->data;
+
+ if (op == CIL_ALL) {
+ *out = cil_strdup(CIL_KEY_ALL);
+ } else if (op == CIL_RANGE) {
+ __cil_expr_to_string_helper(curr->next, flavor, &s1);
+ __cil_expr_to_string_helper(curr->next->next, flavor, &s2);
+ cil_asprintf(out, "%s %s %s", CIL_KEY_RANGE, s1, s2);
+ free(s1);
+ free(s2);
+ } else {
+ __cil_expr_to_string_helper(curr->next, flavor, &s1);
+
+ if (op == CIL_NOT) {
+ cil_asprintf(out, "%s %s", CIL_KEY_NOT, s1);
+ free(s1);
+ } else {
+ char *opstr = "";
+
+ __cil_expr_to_string_helper(curr->next->next, flavor, &s2);
+
+ if (op == CIL_OR) {
+ opstr = CIL_KEY_OR;
+ } else if (op == CIL_AND) {
+ opstr = CIL_KEY_AND;
+ } else if (op == CIL_XOR) {
+ opstr = CIL_KEY_XOR;
+ }
+
+ cil_asprintf(out, "%s %s %s", opstr, s1, s2);
+ free(s1);
+ free(s2);
+ }
+ }
+ } else {
+ char *c1 = NULL;
+ char *c2 = NULL;
+ __cil_expr_to_string_helper(curr, flavor, &c1);
+ for (curr = curr->next; curr; curr = curr->next) {
+ __cil_expr_to_string_helper(curr, flavor, &s1);
+ cil_asprintf(&c2, "%s %s", c1, s1);
+ free(c1);
+ free(s1);
+ c1 = c2;
+ }
+ *out = c1;
+ }
+}
+
+static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail);
+
+static int __cil_cond_item_to_sepol_expr(policydb_t *pdb, struct cil_list_item *item, cond_expr_t **head, cond_expr_t **tail)
+{
+ if (item == NULL) {
+ goto exit;
+ } else if (item->flavor == CIL_DATUM) {
+ char *key = DATUM(item->data)->fqn;
+ cond_bool_datum_t *sepol_bool = hashtab_search(pdb->p_bools.table, key);
+ if (sepol_bool == NULL) {
+ cil_log(CIL_INFO, "Failed to find boolean\n");
+ goto exit;
+ }
+ *head = cil_malloc(sizeof(cond_expr_t));
+ (*head)->next = NULL;
+ (*head)->expr_type = COND_BOOL;
+ (*head)->bool = sepol_bool->s.value;
+ *tail = *head;
+ } else if (item->flavor == CIL_LIST) {
+ struct cil_list *l = item->data;
+ int rc = __cil_cond_expr_to_sepol_expr_helper(pdb, l, head, tail);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *item = cil_expr->head;
+ enum cil_flavor flavor = cil_expr->flavor;
+ cond_expr_t *op, *h1, *h2, *t1, *t2;
+
+ if (flavor != CIL_BOOL) {
+ cil_log(CIL_INFO, "Expected boolean expression\n");
+ goto exit;
+ }
+
+ if (item == NULL) {
+ goto exit;
+ } else if (item->flavor == CIL_OP) {
+ enum cil_flavor cil_op = (enum cil_flavor)item->data;
+
+ op = cil_malloc(sizeof(*op));
+ op->bool = 0;
+ op->next = NULL;
+
+ switch (cil_op) {
+ case CIL_NOT:
+ op->expr_type = COND_NOT;
+ break;
+ case CIL_OR:
+ op->expr_type = COND_OR;
+ break;
+ case CIL_AND:
+ op->expr_type = COND_AND;
+ break;
+ case CIL_XOR:
+ op->expr_type = COND_XOR;
+ break;
+ case CIL_EQ:
+ op->expr_type = COND_EQ;
+ break;
+ case CIL_NEQ:
+ op->expr_type = COND_NEQ;
+ break;
+ default:
+ goto exit;
+ }
+
+ rc = __cil_cond_item_to_sepol_expr(pdb, item->next, &h1, &t1);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get first operand of conditional expression\n");
+ free(op);
+ goto exit;
+ }
+
+ if (cil_op == CIL_NOT) {
+ *head = h1;
+ t1->next = op;
+ *tail = op;
+ } else {
+ rc = __cil_cond_item_to_sepol_expr(pdb, item->next->next, &h2, &t2);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get second operand of conditional expression\n");
+ free(op);
+ cond_expr_destroy(h1);
+ goto exit;
+ }
+
+ *head = h1;
+ t1->next = h2;
+ t2->next = op;
+ *tail = op;
+ }
+ } else {
+ rc = __cil_cond_item_to_sepol_expr(pdb, item, &h1, &t1);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get initial item in conditional list\n");
+ goto exit;
+ }
+ *head = h1;
+ for (item = item->next; item; item = item->next) {
+ rc = __cil_cond_item_to_sepol_expr(pdb, item, &h2, &t2);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get item in conditional list\n");
+ cond_expr_destroy(*head);
+ goto exit;
+ }
+ op = cil_malloc(sizeof(*op));
+ op->bool = 0;
+ op->next = NULL;
+ op->expr_type = COND_OR;
+ t1->next = h2;
+ t2->next = op;
+ t1 = op;
+ }
+ *tail = t1;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_cond_expr_to_sepol_expr(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **sepol_expr)
+{
+ int rc;
+ cond_expr_t *head, *tail;
+
+ rc = __cil_cond_expr_to_sepol_expr_helper(pdb, cil_expr, &head, &tail);
+ if (rc != SEPOL_OK) {
+ return SEPOL_ERR;
+ }
+ *sepol_expr = head;
+
+ return SEPOL_OK;
+}
+
+int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_booleanif bool_args;
+ struct cil_booleanif *cil_boolif = (struct cil_booleanif*)node->data;
+ struct cil_tree_node *cb_node = node->cl_head;
+ struct cil_tree_node *true_node = NULL;
+ struct cil_tree_node *false_node = NULL;
+ struct cil_tree_node *tmp_node = NULL;
+ cond_node_t *tmp_cond = NULL;
+ cond_node_t *cond_node = NULL;
+ int was_created;
+ int swapped = CIL_FALSE;
+ cond_av_list_t tmp_cl;
+
+ tmp_cond = cond_node_create(pdb, NULL);
+ if (tmp_cond == NULL) {
+ rc = SEPOL_ERR;
+ cil_tree_log(node, CIL_INFO, "Failed to create sepol conditional node");
+ goto exit;
+ }
+
+ rc = __cil_cond_expr_to_sepol_expr(pdb, cil_boolif->datum_expr, &tmp_cond->expr);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_INFO, "Failed to convert CIL conditional expression to sepol expression");
+ goto exit;
+ }
+
+ tmp_cond->true_list = &tmp_cl;
+
+ rc = cond_normalize_expr(pdb, tmp_cond);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (tmp_cond->false_list != NULL) {
+ tmp_cond->true_list = NULL;
+ swapped = CIL_TRUE;
+ }
+
+ cond_node = cond_node_find(pdb, tmp_cond, pdb->cond_list, &was_created);
+ if (cond_node == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (was_created) {
+ cond_node->next = pdb->cond_list;
+ pdb->cond_list = cond_node;
+ }
+
+ cond_expr_destroy(tmp_cond->expr);
+ free(tmp_cond);
+
+ for (cb_node = node->cl_head; cb_node != NULL; cb_node = cb_node->next) {
+ if (cb_node->flavor == CIL_CONDBLOCK) {
+ struct cil_condblock *cb = cb_node->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ true_node = cb_node;
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ false_node = cb_node;
+ }
+ }
+ }
+
+ if (swapped) {
+ tmp_node = true_node;
+ true_node = false_node;
+ false_node = tmp_node;
+ }
+
+ bool_args.db = db;
+ bool_args.pdb = pdb;
+ bool_args.cond_node = cond_node;
+ bool_args.filename_trans_table = filename_trans_table;
+
+ if (true_node != NULL) {
+ bool_args.cond_flavor = CIL_CONDTRUE;
+ rc = cil_tree_walk(true_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(true_node, CIL_ERR, "Failure while walking true conditional block");
+ goto exit;
+ }
+ }
+
+ if (false_node != NULL) {
+ bool_args.cond_flavor = CIL_CONDFALSE;
+ rc = cil_tree_walk(false_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(false_node, CIL_ERR, "Failure while walking false conditional block");
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table)
+{
+ int rc = SEPOL_ERR;
+ role_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_obj = NULL;
+ struct cil_list *class_list;
+ role_datum_t *sepol_result = NULL;
+ role_trans_t *new = NULL;
+ uint32_t *new_role = NULL;
+ ebitmap_t role_bitmap, type_bitmap;
+ ebitmap_node_t *rnode, *tnode;
+ unsigned int i, j;
+ struct cil_list_item *c;
+
+ rc = __cil_expand_role(DATUM(roletrans->src), &role_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_expand_type(roletrans->tgt, &type_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ class_list = cil_expand_class(roletrans->obj);
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(roletrans->result), &sepol_result);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&role_bitmap, rnode, i) {
+ if (!ebitmap_get_bit(&role_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&type_bitmap, tnode, j) {
+ if (!ebitmap_get_bit(&type_bitmap, j)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ cil_list_for_each(c, class_list) {
+ int add = CIL_TRUE;
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+ if (rc != SEPOL_OK) goto exit;
+
+ new = cil_malloc(sizeof(*new));
+ memset(new, 0, sizeof(*new));
+ new->role = sepol_src->s.value;
+ new->type = sepol_tgt->s.value;
+ new->tclass = sepol_obj->s.value;
+ new->new_role = sepol_result->s.value;
+
+ rc = SEPOL_OK;
+ rc = hashtab_insert(role_trans_table, (hashtab_key_t)new, &(new->new_role));
+ if (rc != SEPOL_OK) {
+ if (rc == SEPOL_EEXIST) {
+ add = CIL_FALSE;
+ new_role = hashtab_search(role_trans_table, (hashtab_key_t)new);
+ if (new->new_role != *new_role) {
+ cil_log(CIL_ERR, "Conflicting role transition rules\n");
+ } else {
+ rc = SEPOL_OK;
+ }
+ } else {
+ cil_log(CIL_ERR, "Out of memory\n");
+ }
+ }
+
+ if (add == CIL_TRUE) {
+ new->next = pdb->role_tr;
+ pdb->role_tr = new;
+ } else {
+ free(new);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&role_bitmap);
+ ebitmap_destroy(&type_bitmap);
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return rc;
+}
+
+int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow)
+{
+ int rc = SEPOL_ERR;
+ role_datum_t *sepol_src = NULL;
+ role_datum_t *sepol_tgt = NULL;
+ role_allow_t *sepol_roleallow = NULL;
+ ebitmap_t src_bitmap, tgt_bitmap;
+ ebitmap_node_t *node1, *node2;
+ unsigned int i, j;
+
+ rc = __cil_expand_role(roleallow->src, &src_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_expand_role(roleallow->tgt, &tgt_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&src_bitmap, node1, i) {
+ if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+ if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[j]), &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_roleallow = cil_malloc(sizeof(*sepol_roleallow));
+ memset(sepol_roleallow, 0, sizeof(role_allow_t));
+ sepol_roleallow->role = sepol_src->s.value;
+ sepol_roleallow->new_role = sepol_tgt->s.value;
+
+ sepol_roleallow->next = pdb->role_allow;
+ pdb->role_allow = sepol_roleallow;
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&src_bitmap);
+ ebitmap_destroy(&tgt_bitmap);
+ return rc;
+}
+
+int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr)
+{
+ int rc = SEPOL_ERR;
+
+ if (expr_flavor == CIL_USER) {
+ user_datum_t *sepol_user = NULL;
+ ebitmap_t user_bitmap;
+ ebitmap_node_t *unode;
+ unsigned int i;
+
+ rc = __cil_expand_user(item->data, &user_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&user_bitmap, unode, i) {
+ if (!ebitmap_get_bit(&user_bitmap, i)) {
+ continue;
+ }
+
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(db->val_to_user[i]), &sepol_user);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&user_bitmap);
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&expr->names, sepol_user->s.value - 1, 1)) {
+ ebitmap_destroy(&user_bitmap);
+ goto exit;
+ }
+ }
+ ebitmap_destroy(&user_bitmap);
+ } else if (expr_flavor == CIL_ROLE) {
+ role_datum_t *sepol_role = NULL;
+ ebitmap_t role_bitmap;
+ ebitmap_node_t *rnode;
+ unsigned int i;
+
+ rc = __cil_expand_role(item->data, &role_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&role_bitmap, rnode, i) {
+ if (!ebitmap_get_bit(&role_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&role_bitmap);
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&expr->names, sepol_role->s.value - 1, 1)) {
+ ebitmap_destroy(&role_bitmap);
+ goto exit;
+ }
+ }
+ ebitmap_destroy(&role_bitmap);
+ } else if (expr_flavor == CIL_TYPE) {
+ type_datum_t *sepol_type = NULL;
+ ebitmap_t type_bitmap;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ if (pdb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ rc = __cil_get_sepol_type_datum(pdb, item->data, &sepol_type);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&type_bitmap);
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&expr->type_names->types, sepol_type->s.value - 1, 1)) {
+ ebitmap_destroy(&type_bitmap);
+ goto exit;
+ }
+ }
+
+ rc = __cil_expand_type(item->data, &type_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&type_bitmap, tnode, i) {
+ if (!ebitmap_get_bit(&type_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&type_bitmap);
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(&expr->names, sepol_type->s.value - 1, 1)) {
+ ebitmap_destroy(&type_bitmap);
+ goto exit;
+ }
+ }
+ ebitmap_destroy(&type_bitmap);
+ } else {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *l_item = op_item->next;
+ struct cil_list_item *r_item = op_item->next->next;
+
+ enum cil_flavor l_operand = (enum cil_flavor)l_item->data;
+
+ switch (l_operand) {
+ case CIL_CONS_U1:
+ expr->attr = CEXPR_USER;
+ break;
+ case CIL_CONS_U2:
+ expr->attr = CEXPR_USER | CEXPR_TARGET;
+ break;
+ case CIL_CONS_U3:
+ expr->attr = CEXPR_USER | CEXPR_XTARGET;
+ break;
+ case CIL_CONS_R1:
+ expr->attr = CEXPR_ROLE;
+ break;
+ case CIL_CONS_R2:
+ expr->attr = CEXPR_ROLE | CEXPR_TARGET;
+ break;
+ case CIL_CONS_R3:
+ expr->attr = CEXPR_ROLE | CEXPR_XTARGET;
+ break;
+ case CIL_CONS_T1:
+ expr->attr = CEXPR_TYPE;
+ break;
+ case CIL_CONS_T2:
+ expr->attr = CEXPR_TYPE | CEXPR_TARGET;
+ break;
+ case CIL_CONS_T3:
+ expr->attr = CEXPR_TYPE | CEXPR_XTARGET;
+ break;
+ case CIL_CONS_L1: {
+ enum cil_flavor r_operand = (enum cil_flavor)r_item->data;
+
+ if (r_operand == CIL_CONS_L2) {
+ expr->attr = CEXPR_L1L2;
+ } else if (r_operand == CIL_CONS_H1) {
+ expr->attr = CEXPR_L1H1;
+ } else {
+ expr->attr = CEXPR_L1H2;
+ }
+ break;
+ }
+ case CIL_CONS_L2:
+ expr->attr = CEXPR_L2H2;
+ break;
+ case CIL_CONS_H1: {
+ enum cil_flavor r_operand = (enum cil_flavor)r_item->data;
+ if (r_operand == CIL_CONS_L2) {
+ expr->attr = CEXPR_H1L2;
+ } else {
+ expr->attr = CEXPR_H1H2;
+ }
+ break;
+ }
+ default:
+ goto exit;
+ break;
+ }
+
+ if (r_item->flavor == CIL_CONS_OPERAND) {
+ expr->expr_type = CEXPR_ATTR;
+ } else {
+ expr->expr_type = CEXPR_NAMES;
+ if (r_item->flavor == CIL_DATUM) {
+ rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, r_item, expr_flavor, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else if (r_item->flavor == CIL_LIST) {
+ struct cil_list *r_expr = r_item->data;
+ struct cil_list_item *curr;
+ cil_list_for_each(curr, r_expr) {
+ rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, curr, expr_flavor, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *item;
+ enum cil_flavor flavor;
+ constraint_expr_t *op, *h1, *h2, *t1, *t2;
+ int is_leaf = CIL_FALSE;
+
+ if (cil_expr == NULL) {
+ return SEPOL_ERR;
+ }
+
+ item = cil_expr->head;
+ flavor = cil_expr->flavor;
+
+ op = cil_malloc(sizeof(constraint_expr_t));
+ rc = constraint_expr_init(op);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ enum cil_flavor cil_op = (enum cil_flavor)item->data;
+ switch (cil_op) {
+ case CIL_NOT:
+ op->expr_type = CEXPR_NOT;
+ break;
+ case CIL_AND:
+ op->expr_type = CEXPR_AND;
+ break;
+ case CIL_OR:
+ op->expr_type = CEXPR_OR;
+ break;
+ case CIL_EQ:
+ op->op = CEXPR_EQ;
+ is_leaf = CIL_TRUE;
+ break;
+ case CIL_NEQ:
+ op->op = CEXPR_NEQ;
+ is_leaf = CIL_TRUE;
+ break;
+ case CIL_CONS_DOM:
+ op->op = CEXPR_DOM;
+ is_leaf = CIL_TRUE;
+ break;
+ case CIL_CONS_DOMBY:
+ op->op = CEXPR_DOMBY;
+ is_leaf = CIL_TRUE;
+ break;
+ case CIL_CONS_INCOMP:
+ op->op = CEXPR_INCOMP;
+ is_leaf = CIL_TRUE;
+ break;
+ default:
+ goto exit;
+ }
+
+ if (is_leaf == CIL_TRUE) {
+ rc = __cil_constrain_expr_leaf_to_sepol_expr(pdb, db, item, flavor, op);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ *head = op;
+ *tail = op;
+ } else if (cil_op == CIL_NOT) {
+ struct cil_list *l_expr = item->next->data;
+ rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ t1->next = op;
+ *head = h1;
+ *tail = op;
+ } else {
+ struct cil_list *l_expr = item->next->data;
+ struct cil_list *r_expr = item->next->next->data;
+ rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, r_expr, &h2, &t2);
+ if (rc != SEPOL_OK) {
+ constraint_expr_destroy(h1);
+ goto exit;
+ }
+ t1->next = h2;
+ t2->next = op;
+ *head = h1;
+ *tail = op;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ constraint_expr_destroy(op);
+ return SEPOL_ERR;
+}
+
+int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr)
+{
+ int rc;
+ constraint_expr_t *head, *tail;
+
+ rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, cil_expr, &head, &tail);
+ if (rc != SEPOL_OK) {
+ return SEPOL_ERR;
+ }
+
+ *sepol_expr = head;
+
+ return SEPOL_OK;
+}
+
+int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr)
+{
+ int rc = SEPOL_ERR;
+ constraint_node_t *sepol_constrain = NULL;
+ constraint_expr_t *sepol_expr = NULL;
+ class_datum_t *sepol_class = NULL;
+
+ sepol_constrain = cil_malloc(sizeof(*sepol_constrain));
+ memset(sepol_constrain, 0, sizeof(constraint_node_t));
+
+ rc = __cil_get_sepol_class_datum(pdb, class, &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_perms_to_datum(perms, sepol_class, &sepol_constrain->permissions);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ sepol_constrain->expr = sepol_expr;
+ sepol_constrain->next = sepol_class->constraints;
+ sepol_class->constraints = sepol_constrain;
+
+ return SEPOL_OK;
+
+exit:
+ free(sepol_constrain);
+ return rc;
+}
+
+int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ rc = cil_constrain_to_policydb_helper(pdb, db, DATUM(cp->class), cp->perms, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ rc = cil_constrain_expand(pdb, db, cmp->classperms, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = cil_constrain_expand(pdb, db, cp->classperms, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain)
+{
+ int rc = SEPOL_ERR;
+ rc = cil_constrain_expand(pdb, db, cil_constrain->classperms, cil_constrain->datum_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to insert constraint into policydb\n");
+ return rc;
+}
+
+int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list *expr = cil_validatetrans->datum_expr;
+ class_datum_t *sepol_class = NULL;
+ struct cil_list *class_list;
+ constraint_node_t *sepol_validatetrans = NULL;
+ constraint_expr_t *sepol_expr = NULL;
+ struct cil_list_item *c;
+
+ class_list = cil_expand_class(cil_validatetrans->class);
+
+ cil_list_for_each(c, class_list) {
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_validatetrans = cil_malloc(sizeof(*sepol_validatetrans));
+ memset(sepol_validatetrans, 0, sizeof(constraint_node_t));
+
+ rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr);
+ if (rc != SEPOL_OK) {
+ free(sepol_validatetrans);
+ goto exit;
+ }
+ sepol_validatetrans->expr = sepol_expr;
+
+ sepol_validatetrans->next = sepol_class->validatetrans;
+ sepol_class->validatetrans = sepol_validatetrans;
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return rc;
+}
+
+int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t *mls_level)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *i;
+ cat_datum_t *sepol_cat = NULL;
+
+ cil_list_for_each(i, cats->datum_expr) {
+ struct cil_tree_node *node = DATUM(i->data)->nodes->head->data;
+ if (node->flavor == CIL_CATSET) {
+ struct cil_list_item *j;
+ struct cil_catset *cs = i->data;
+ cil_list_for_each(j, cs->cats->datum_expr) {
+ rc = __cil_get_sepol_cat_datum(pdb, j->data, &sepol_cat);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ } else {
+ rc = __cil_get_sepol_cat_datum(pdb, i->data, &sepol_cat);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ level_datum_t *sepol_level = NULL;
+ mls_level_t *mls_level = NULL;
+
+ rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level);
+ if (rc != SEPOL_OK) goto exit;
+
+ mls_level = sepol_level->level;
+
+ ebitmap_init(&mls_level->cat);
+
+ if (cil_sens->cats_list) {
+ cil_list_for_each(curr, cil_sens->cats_list) {
+ struct cil_cats *cats = curr->data;
+ rc = __cil_cats_to_mls_level(pdb, cats, mls_level);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n");
+ goto exit;
+ }
+ }
+ }
+
+ sepol_level->defined = 1;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level)
+{
+ int rc = SEPOL_ERR;
+ struct cil_sens *cil_sens = cil_level->sens;
+ struct cil_cats *cats = cil_level->cats;
+ level_datum_t *sepol_level = NULL;
+
+ rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level);
+ if (rc != SEPOL_OK) goto exit;
+
+ mls_level->sens = sepol_level->level->sens;
+
+ ebitmap_init(&mls_level->cat);
+
+ if (cats != NULL) {
+ rc = __cil_cats_to_mls_level(pdb, cats, mls_level);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n");
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+}
+
+int __cil_levelrange_to_mls_range(policydb_t *pdb, struct cil_levelrange *cil_lvlrange, mls_range_t *mls_range)
+{
+ int rc = SEPOL_ERR;
+ struct cil_level *low = cil_lvlrange->low;
+ struct cil_level *high = cil_lvlrange->high;
+ mls_level_t *mls_level = NULL;
+
+ mls_level = &mls_range->level[0];
+
+ rc = cil_level_to_mls_level(pdb, low, mls_level);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ mls_level = &mls_range->level[1];
+
+ rc = cil_level_to_mls_level(pdb, high, mls_level);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_userlevel_userrange_to_policydb(policydb_t *pdb, struct cil_user *cil_user)
+{
+ int rc = SEPOL_ERR;
+ struct cil_level *cil_level = cil_user->dftlevel;
+ struct cil_levelrange *cil_levelrange = cil_user->range;
+ user_datum_t *sepol_user = NULL;
+
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = cil_level_to_mls_level(pdb, cil_level, &sepol_user->exp_dfltlevel);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_levelrange_to_mls_range(pdb, cil_levelrange, &sepol_user->exp_range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_context_to_sepol_context(policydb_t *pdb, struct cil_context *cil_context, context_struct_t *sepol_context)
+{
+ int rc = SEPOL_ERR;
+ struct cil_levelrange *cil_lvlrange = cil_context->range;
+ user_datum_t *sepol_user = NULL;
+ role_datum_t *sepol_role = NULL;
+ type_datum_t *sepol_type = NULL;
+
+ rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_context->user), &sepol_user);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_context->role), &sepol_role);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_context->type), &sepol_type);
+ if (rc != SEPOL_OK) goto exit;
+
+ sepol_context->user = sepol_user->s.value;
+ sepol_context->role = sepol_role->s.value;
+ sepol_context->type = sepol_type->s.value;
+
+ if (pdb->mls == CIL_TRUE) {
+ mls_context_init(sepol_context);
+
+ rc = __cil_levelrange_to_mls_range(pdb, cil_lvlrange, &sepol_context->range);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR,"Problem with MLS\n");
+ mls_context_destroy(sepol_context);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_sidorder_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ unsigned count = 0;
+ ocontext_t *tail = NULL;
+
+ if (db->sidorder == NULL || db->sidorder->head == NULL) {
+ cil_log(CIL_WARN, "No sidorder statement in policy\n");
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(curr, db->sidorder) {
+ struct cil_sid *cil_sid = (struct cil_sid*)curr->data;
+ struct cil_context *cil_context = cil_sid->context;
+
+ if (cil_context != NULL) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_ISID], &tail);
+ count++;
+ new_ocon->sid[0] = count;
+ new_ocon->u.name = cil_strdup(cil_sid->datum.fqn);
+ rc = __cil_context_to_sepol_context(pdb, cil_context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR,"Problem with context for SID %s\n",cil_sid->datum.fqn);
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans, hashtab_t range_trans_table)
+{
+ int rc = SEPOL_ERR;
+ type_datum_t *sepol_src = NULL;
+ type_datum_t *sepol_tgt = NULL;
+ class_datum_t *sepol_class = NULL;
+ struct cil_list *class_list;
+ range_trans_t *new;
+ ebitmap_t src_bitmap, tgt_bitmap;
+ ebitmap_node_t *node1, *node2;
+ unsigned int i, j;
+ struct cil_list_item *c;
+ struct mls_range *o_range = NULL;
+
+ rc = __cil_expand_type(rangetrans->src, &src_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_expand_type(rangetrans->exec, &tgt_bitmap);
+ if (rc != SEPOL_OK) goto exit;
+
+ class_list = cil_expand_class(rangetrans->obj);
+
+ ebitmap_for_each_bit(&src_bitmap, node1, i) {
+ if (!ebitmap_get_bit(&src_bitmap, i)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src);
+ if (rc != SEPOL_OK) goto exit;
+
+ ebitmap_for_each_bit(&tgt_bitmap, node2, j) {
+ if (!ebitmap_get_bit(&tgt_bitmap, j)) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt);
+ if (rc != SEPOL_OK) goto exit;
+
+ cil_list_for_each(c, class_list) {
+ int add = CIL_TRUE;
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ new = cil_malloc(sizeof(*new));
+ memset(new, 0, sizeof(range_trans_t));
+ new->source_type = sepol_src->s.value;
+ new->target_type = sepol_tgt->s.value;
+ new->target_class = sepol_class->s.value;
+ rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, &new->target_range);
+ if (rc != SEPOL_OK) {
+ free(new);
+ goto exit;
+ }
+
+ rc = SEPOL_OK;
+ rc = hashtab_insert(range_trans_table, (hashtab_key_t)new, &(new->target_range));
+ if (rc != SEPOL_OK) {
+ if (rc == SEPOL_EEXIST) {
+ add = CIL_FALSE;
+ o_range = hashtab_search(range_trans_table, (hashtab_key_t)new);
+ if (!mls_range_eq(&new->target_range, o_range)) {
+ cil_log(CIL_ERR, "Conflicting Range transition rules\n");
+ } else {
+ rc = SEPOL_OK;
+ }
+ } else {
+ cil_log(CIL_ERR, "Out of memory\n");
+ }
+ }
+
+ if (add == CIL_TRUE) {
+ new->next = pdb->range_tr;
+ pdb->range_tr = new;
+ } else {
+ mls_range_destroy(&new->target_range);
+ free(new);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ ebitmap_destroy(&src_bitmap);
+ ebitmap_destroy(&tgt_bitmap);
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return rc;
+}
+
+int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < portcons->count; i++) {
+ struct cil_portcon *cil_portcon = portcons->array[i];
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_PORT], &tail);
+
+ switch (cil_portcon->proto) {
+ case CIL_PROTOCOL_UDP:
+ new_ocon->u.port.protocol = IPPROTO_UDP;
+ break;
+ case CIL_PROTOCOL_TCP:
+ new_ocon->u.port.protocol = IPPROTO_TCP;
+ break;
+ case CIL_PROTOCOL_DCCP:
+ new_ocon->u.port.protocol = IPPROTO_DCCP;
+ break;
+ default:
+ /* should not get here */
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ new_ocon->u.port.low_port = cil_portcon->port_low;
+ new_ocon->u.port.high_port = cil_portcon->port_high;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_portcon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < netifcons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NETIF], &tail);
+ struct cil_netifcon *cil_netifcon = netifcons->array[i];
+
+ new_ocon->u.name = cil_strdup(cil_netifcon->interface_str);
+
+ rc = __cil_context_to_sepol_context(pdb, cil_netifcon->if_context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_context_to_sepol_context(pdb, cil_netifcon->packet_context, &new_ocon->context[1]);
+ if (rc != SEPOL_OK) {
+ context_destroy(&new_ocon->context[0]);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+ ocontext_t *tail6 = NULL;
+
+ for (i = 0; i < nodecons->count; i++) {
+ ocontext_t *new_ocon = NULL;
+ struct cil_nodecon *cil_nodecon = nodecons->array[i];
+
+ if (cil_nodecon->addr->family == AF_INET) {
+ new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE], &tail);
+ new_ocon->u.node.addr = cil_nodecon->addr->ip.v4.s_addr;
+ new_ocon->u.node.mask = cil_nodecon->mask->ip.v4.s_addr;
+ } else if (cil_nodecon->addr->family == AF_INET6) {
+ new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE6], &tail6);
+ memcpy(new_ocon->u.node6.addr, &cil_nodecon->addr->ip.v6.s6_addr[0], 16);
+ memcpy(new_ocon->u.node6.mask, &cil_nodecon->mask->ip.v6.s6_addr[0], 16);
+ } else {
+ /* should not get here */
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = __cil_context_to_sepol_context(pdb, cil_nodecon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < fsuses->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_FSUSE], &tail);
+ struct cil_fsuse *cil_fsuse = fsuses->array[i];
+
+ new_ocon->u.name = cil_strdup(cil_fsuse->fs_str);
+ new_ocon->v.behavior = cil_fsuse->type;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_fsuse->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ genfs_t *genfs_tail = NULL;
+ ocontext_t *ocon_tail = NULL;
+
+ for (i = 0; i < genfscons->count; i++) {
+ struct cil_genfscon *cil_genfscon = genfscons->array[i];
+ ocontext_t *new_ocon = cil_malloc(sizeof(ocontext_t));
+ memset(new_ocon, 0, sizeof(ocontext_t));
+
+ if (genfs_tail && strcmp(genfs_tail->fstype, cil_genfscon->fs_str) == 0) {
+ ocon_tail->next = new_ocon;
+ } else {
+ genfs_t *new_genfs = cil_malloc(sizeof(genfs_t));
+ memset(new_genfs, 0, sizeof(genfs_t));
+ new_genfs->fstype = cil_strdup(cil_genfscon->fs_str);
+ new_genfs->head = new_ocon;
+
+ if (genfs_tail) {
+ genfs_tail->next = new_genfs;
+ } else {
+ pdb->genfs = new_genfs;
+ }
+ genfs_tail = new_genfs;
+ }
+
+ ocon_tail = new_ocon;
+
+ new_ocon->u.name = cil_strdup(cil_genfscon->path_str);
+
+ rc = __cil_context_to_sepol_context(pdb, cil_genfscon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < pirqcons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PIRQ], &tail);
+ struct cil_pirqcon *cil_pirqcon = pirqcons->array[i];
+
+ new_ocon->u.pirq = cil_pirqcon->pirq;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_pirqcon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < iomemcons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOMEM], &tail);
+ struct cil_iomemcon *cil_iomemcon = iomemcons->array[i];
+
+ new_ocon->u.iomem.low_iomem = cil_iomemcon->iomem_low;
+ new_ocon->u.iomem.high_iomem = cil_iomemcon->iomem_high;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_iomemcon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < ioportcons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOPORT], &tail);
+ struct cil_ioportcon *cil_ioportcon = ioportcons->array[i];
+
+ new_ocon->u.ioport.low_ioport = cil_ioportcon->ioport_low;
+ new_ocon->u.ioport.high_ioport = cil_ioportcon->ioport_high;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_ioportcon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < pcidevicecons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PCIDEVICE], &tail);
+ struct cil_pcidevicecon *cil_pcidevicecon = pcidevicecons->array[i];
+
+ new_ocon->u.device = cil_pcidevicecon->dev;
+
+ rc = __cil_context_to_sepol_context(pdb, cil_pcidevicecon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_devicetreecon_to_policydb(policydb_t *pdb, struct cil_sort *devicetreecons)
+{
+ int rc = SEPOL_ERR;
+ uint32_t i = 0;
+ ocontext_t *tail = NULL;
+
+ for (i = 0; i < devicetreecons->count; i++) {
+ ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_DEVICETREE], &tail);
+ struct cil_devicetreecon *cil_devicetreecon = devicetreecons->array[i];
+
+ new_ocon->u.name = cil_strdup(cil_devicetreecon->path);
+
+ rc = __cil_context_to_sepol_context(pdb, cil_devicetreecon->context, &new_ocon->context[0]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def)
+{
+ struct cil_list_item *curr;
+ class_datum_t *sepol_class;
+ struct cil_list *class_list;
+
+ cil_list_for_each(curr, def->class_datums) {
+ struct cil_list_item *c;
+
+ class_list = cil_expand_class(curr->data);
+
+ cil_list_for_each(c, class_list) {
+ int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ switch (def->flavor) {
+ case CIL_DEFAULTUSER:
+ if (!sepol_class->default_user) {
+ sepol_class->default_user = def->object;
+ } else if (sepol_class->default_user != (char)def->object) {
+ cil_log(CIL_ERR,"User default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+ goto exit;
+ }
+ break;
+ case CIL_DEFAULTROLE:
+ if (!sepol_class->default_role) {
+ sepol_class->default_role = def->object;
+ } else if (sepol_class->default_role != (char)def->object) {
+ cil_log(CIL_ERR,"Role default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+ goto exit;
+ }
+ break;
+ case CIL_DEFAULTTYPE:
+ if (!sepol_class->default_type) {
+ sepol_class->default_type = def->object;
+ } else if (sepol_class->default_type != (char)def->object) {
+ cil_log(CIL_ERR,"Type default labeling for class %s already specified\n",DATUM(c->data)->fqn);
+ goto exit;
+ }
+ break;
+ default:
+ goto exit;
+ }
+ }
+
+ cil_list_destroy(&class_list, CIL_FALSE);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return SEPOL_ERR;
+}
+
+int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def)
+{
+ struct cil_list_item *curr;
+ class_datum_t *sepol_class;
+ struct cil_list *class_list;
+
+ cil_list_for_each(curr, def->class_datums) {
+ struct cil_list_item *c;
+
+ class_list = cil_expand_class(curr->data);
+
+ cil_list_for_each(c, class_list) {
+ int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (!sepol_class->default_range) {
+ sepol_class->default_range = def->object_range;
+ } else if (sepol_class->default_range != (char)def->object_range) {
+ cil_log(CIL_ERR,"Range default labeling for class %s already specified\n", DATUM(curr->data)->fqn);
+ goto exit;
+ }
+ }
+
+ cil_list_destroy(&class_list, CIL_FALSE);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_list_destroy(&class_list, CIL_FALSE);
+ return SEPOL_ERR;
+}
+
+int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args)
+{
+ int rc = SEPOL_OK;
+ int pass;
+ struct cil_args_binary *args = extra_args;
+ const struct cil_db *db;
+ policydb_t *pdb;
+ hashtab_t filename_trans_table;
+ hashtab_t range_trans_table;
+ hashtab_t role_trans_table;
+ void **type_value_to_cil;
+
+ db = args->db;
+ pdb = args->pdb;
+ pass = args->pass;
+ filename_trans_table = args->filename_trans_table;
+ range_trans_table = args->range_trans_table;
+ role_trans_table = args->role_trans_table;
+ type_value_to_cil = args->type_value_to_cil;
+
+ if (node->flavor >= CIL_MIN_DECLARATIVE) {
+ if (node != DATUM(node->data)->nodes->head->data) {
+ goto exit;
+ }
+ }
+
+ switch (pass) {
+ case 1:
+ switch (node->flavor) {
+ case CIL_ROLE:
+ rc = cil_role_to_policydb(pdb, node->data);
+ break;
+ case CIL_TYPE:
+ rc = cil_type_to_policydb(pdb, node->data, type_value_to_cil);
+ break;
+ case CIL_TYPEATTRIBUTE:
+ rc = cil_typeattribute_to_policydb(pdb, node->data, type_value_to_cil);
+ break;
+ case CIL_POLICYCAP:
+ rc = cil_policycap_to_policydb(pdb, node->data);
+ break;
+ case CIL_USER:
+ rc = cil_user_to_policydb(pdb, node->data);
+ break;
+ case CIL_BOOL:
+ rc = cil_bool_to_policydb(pdb, node->data);
+ break;
+ case CIL_CATALIAS:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_catalias_to_policydb(pdb, node->data);
+ }
+ break;
+ case CIL_SENS:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_sepol_level_define(pdb, node->data);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (node->flavor) {
+ case CIL_TYPE:
+ rc = cil_type_bounds_to_policydb(pdb, node->data);
+ break;
+ case CIL_TYPEALIAS:
+ rc = cil_typealias_to_policydb(pdb, node->data);
+ break;
+ case CIL_TYPEPERMISSIVE:
+ rc = cil_typepermissive_to_policydb(pdb, node->data);
+ break;
+ case CIL_TYPEATTRIBUTE:
+ rc = cil_typeattribute_to_bitmap(pdb, db, node->data);
+ break;
+ case CIL_SENSALIAS:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_sensalias_to_policydb(pdb, node->data);
+ }
+ break;
+ case CIL_ROLE:
+ rc = cil_role_bounds_to_policydb(pdb, node->data);
+ if (rc != SEPOL_OK) goto exit;
+ rc = cil_roletype_to_policydb(pdb, db, node->data);
+ break;
+ case CIL_USER:
+ rc = cil_user_bounds_to_policydb(pdb, node->data);
+ if (rc != SEPOL_OK) goto exit;
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_userlevel_userrange_to_policydb(pdb, node->data);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ rc = cil_userrole_to_policydb(pdb, db, node->data);
+ break;
+ case CIL_TYPE_RULE:
+ rc = cil_type_rule_to_policydb(pdb, db, node->data);
+ break;
+ case CIL_AVRULE:
+ case CIL_AVRULEX: {
+ struct cil_avrule *rule = node->data;
+ if (db->disable_neverallow != CIL_TRUE && rule->rule_kind == CIL_AVRULE_NEVERALLOW) {
+ struct cil_list *neverallows = args->neverallows;
+ cil_list_prepend(neverallows, CIL_LIST_ITEM, node);
+ }
+ break;
+ }
+ case CIL_ROLETRANSITION:
+ rc = cil_roletrans_to_policydb(pdb, db, node->data, role_trans_table);
+ break;
+ case CIL_ROLEATTRIBUTESET:
+ /*rc = cil_roleattributeset_to_policydb(pdb, node->data);*/
+ break;
+ case CIL_NAMETYPETRANSITION:
+ rc = cil_typetransition_to_policydb(pdb, db, node->data, filename_trans_table);
+ break;
+ case CIL_CONSTRAIN:
+ rc = cil_constrain_to_policydb(pdb, db, node->data);
+ break;
+ case CIL_MLSCONSTRAIN:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_constrain_to_policydb(pdb, db, node->data);
+ }
+ break;
+ case CIL_VALIDATETRANS:
+ rc = cil_validatetrans_to_policydb(pdb, db, node->data);
+ break;
+ case CIL_MLSVALIDATETRANS:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_validatetrans_to_policydb(pdb, db, node->data);
+ }
+ break;
+ case CIL_RANGETRANSITION:
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_rangetransition_to_policydb(pdb, db, node->data, range_trans_table);
+ }
+ break;
+ case CIL_DEFAULTUSER:
+ case CIL_DEFAULTROLE:
+ case CIL_DEFAULTTYPE:
+ rc = cil_default_to_policydb(pdb, node->data);
+ break;
+ case CIL_DEFAULTRANGE:
+ rc = cil_defaultrange_to_policydb(pdb, node->data);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (node->flavor) {
+ case CIL_BOOLEANIF:
+ rc = cil_booleanif_to_policydb(pdb, db, node, filename_trans_table);
+ break;
+ case CIL_AVRULE: {
+ struct cil_avrule *rule = node->data;
+ if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+ rc = cil_avrule_to_policydb(pdb, db, node->data);
+ }
+ }
+ break;
+ case CIL_AVRULEX: {
+ struct cil_avrule *rule = node->data;
+ if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+ rc = cil_avrulex_to_hashtable(pdb, db, node->data, args);
+ }
+ }
+ break;
+ case CIL_ROLEALLOW:
+ rc = cil_roleallow_to_policydb(pdb, db, node->data);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+exit:
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Binary policy creation failed");
+ }
+ return rc;
+}
+
+int __cil_binary_create_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ if (node->flavor == CIL_BLOCK) {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ } else if (node->flavor == CIL_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ } else if (node->flavor == CIL_BOOLEANIF) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+
+ rc = __cil_node_to_policydb(node, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_portcon_to_policydb(pdb, db->portcon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_netifcon_to_policydb(pdb, db->netifcon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_nodecon_to_policydb(pdb, db->nodecon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fsuse_to_policydb(pdb, db->fsuse);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_genfscon_to_policydb(pdb, db->genfscon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (db->target_platform == SEPOL_TARGET_XEN) {
+ rc = cil_pirqcon_to_policydb(pdb, db->pirqcon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_iomemcon_to_policydb(pdb, db->iomemcon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_ioportcon_to_policydb(pdb, db->ioportcon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_pcidevicecon_to_policydb(pdb, db->pcidevicecon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_devicetreecon_to_policydb(pdb, db->devicetreecon);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ return SEPOL_OK;
+exit:
+ return rc;
+}
+
+int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ common_datum_t *common = (common_datum_t *)datum;
+
+ if (common->s.value < 1 || common->s.value > pdb->p_commons.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_common_val_to_name[common->s.value - 1] = (char *)key;
+
+ return 0;
+}
+
+int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ class_datum_t *class = (class_datum_t *)datum;
+
+ if (class->s.value < 1 || class->s.value > pdb->p_classes.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_class_val_to_name[class->s.value - 1] = (char *)key;
+ pdb->class_val_to_struct[class->s.value - 1] = class;
+
+ return 0;
+}
+
+int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ role_datum_t *role = (role_datum_t *)datum;
+
+ if (role->s.value < 1 || role->s.value > pdb->p_roles.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_role_val_to_name[role->s.value - 1] = (char *)key;
+ pdb->role_val_to_struct[role->s.value - 1] = role;
+
+ return 0;
+}
+
+int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ type_datum_t *type = (type_datum_t *)datum;
+
+ if (type->s.value < 1 || type->s.value > pdb->p_types.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_type_val_to_name[type->s.value - 1] = (char *)key;
+ pdb->type_val_to_struct[type->s.value - 1] = type;
+
+ return 0;
+}
+
+int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ user_datum_t *user = (user_datum_t *)datum;
+
+ if (user->s.value < 1 || user->s.value > pdb->p_users.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_user_val_to_name[user->s.value - 1] = (char *)key;
+ pdb->user_val_to_struct[user->s.value - 1] = user;
+
+ return 0;
+}
+
+int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ cond_bool_datum_t *bool = (cond_bool_datum_t *)datum;
+
+ if (bool->s.value < 1 || bool->s.value > pdb->p_bools.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_bool_val_to_name[bool->s.value - 1] = (char *)key;
+ pdb->bool_val_to_struct[bool->s.value - 1] = bool;
+
+ return 0;
+}
+
+int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ level_datum_t *level = (level_datum_t *)datum;
+
+ if (level->level->sens < 1 || level->level->sens > pdb->p_levels.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_sens_val_to_name[level->level->sens - 1] = (char *)key;
+
+ return 0;
+}
+
+int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ policydb_t *pdb = data;
+ cat_datum_t *cat = (cat_datum_t *)datum;
+
+ if (cat->s.value < 1 || cat->s.value > pdb->p_cats.nprim) {
+ return -EINVAL;
+ }
+ pdb->p_cat_val_to_name[cat->s.value - 1] = (char *)key;
+
+ return 0;
+}
+
+int __cil_policydb_val_arrays_create(policydb_t *policydb)
+{
+ int rc = SEPOL_ERR;
+
+ policydb->p_common_val_to_name = cil_malloc(sizeof(char *) * policydb->p_commons.nprim);
+ rc = hashtab_map(policydb->p_commons.table, &__cil_common_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_class_val_to_name = cil_malloc(sizeof(char *) * policydb->p_classes.nprim);
+ policydb->class_val_to_struct = cil_malloc(sizeof(class_datum_t *) * policydb->p_classes.nprim);
+ rc = hashtab_map(policydb->p_classes.table, &__cil_class_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_role_val_to_name = cil_malloc(sizeof(char *) * policydb->p_roles.nprim);
+ policydb->role_val_to_struct = cil_malloc(sizeof(role_datum_t *) * policydb->p_roles.nprim);
+ rc = hashtab_map(policydb->p_roles.table, &__cil_role_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_type_val_to_name = cil_malloc(sizeof(char *) * policydb->p_types.nprim);
+ policydb->type_val_to_struct = cil_malloc(sizeof(type_datum_t *) * policydb->p_types.nprim);
+ rc = hashtab_map(policydb->p_types.table, &__cil_type_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_user_val_to_name = cil_malloc(sizeof(char *) * policydb->p_users.nprim);
+ policydb->user_val_to_struct = cil_malloc(sizeof(user_datum_t *) * policydb->p_users.nprim);
+ rc = hashtab_map(policydb->p_users.table, &__cil_user_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_bool_val_to_name = cil_malloc(sizeof(char *) * policydb->p_bools.nprim);
+ policydb->bool_val_to_struct = cil_malloc(sizeof(cond_bool_datum_t *) * policydb->p_bools.nprim);
+ rc = hashtab_map(policydb->p_bools.table, &__cil_bool_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_sens_val_to_name = cil_malloc(sizeof(char *) * policydb->p_levels.nprim);
+ rc = hashtab_map(policydb->p_levels.table, &__cil_level_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ policydb->p_cat_val_to_name = cil_malloc(sizeof(char *) * policydb->p_cats.nprim);
+ rc = hashtab_map(policydb->p_cats.table, &__cil_cat_val_array_insert, policydb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+static void __cil_set_conditional_state_and_flags(policydb_t *pdb)
+{
+ cond_node_t *cur;
+
+ for (cur = pdb->cond_list; cur != NULL; cur = cur->next) {
+ int new_state;
+ cond_av_list_t *c;
+
+ new_state = cond_evaluate_expr(pdb, cur->expr);
+
+ cur->cur_state = new_state;
+
+ if (new_state == -1) {
+ cil_log(CIL_WARN, "Expression result was undefined - disabling all rules\n");
+ }
+
+ for (c = cur->true_list; c != NULL; c = c->next) {
+ if (new_state <= 0) {
+ c->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ c->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+
+ for (c = cur->false_list; c != NULL; c = c->next) {
+ if (new_state) { /* -1 or 1 */
+ c->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ c->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+ }
+}
+
+int __cil_policydb_create(const struct cil_db *db, struct sepol_policydb **spdb)
+{
+ int rc;
+ struct policydb *pdb = NULL;
+
+ rc = sepol_policydb_create(spdb);
+ if (rc < 0) {
+ cil_log(CIL_ERR, "Failed to create policy db\n");
+ // spdb could be a dangling pointer at this point, so reset it so
+ // callers of this function don't need to worry about freeing garbage
+ *spdb = NULL;
+ goto exit;
+ }
+
+ pdb = &(*spdb)->p;
+
+ pdb->policy_type = POLICY_KERN;
+ pdb->target_platform = db->target_platform;
+ pdb->policyvers = db->policy_version;
+ pdb->handle_unknown = db->handle_unknown;
+ pdb->mls = db->mls;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int __cil_policydb_init(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+ int rc = SEPOL_ERR;
+
+ // these flags should get set in __cil_policydb_create. However, for
+ // backwards compatability, it is possible that __cil_policydb_create is
+ // never called. So, they must also be set here.
+ pdb->handle_unknown = db->handle_unknown;
+ pdb->mls = db->mls;
+
+ rc = cil_classorder_to_policydb(pdb, db, class_value_to_cil, perm_value_to_cil);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (pdb->mls == CIL_TRUE) {
+ rc = cil_catorder_to_policydb(pdb, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_sensitivityorder_to_policydb(pdb, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = avtab_alloc(&pdb->te_avtab, MAX_AVTAB_SIZE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = avtab_alloc(&pdb->te_cond_avtab, MAX_AVTAB_SIZE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+
+ return rc;
+}
+
+static unsigned int filename_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+ filename_trans_t *k = (filename_trans_t *)key;
+ return ((k->tclass + (k->ttype << 2) +
+ (k->stype << 9)) & (h->size - 1));
+}
+
+static int filename_trans_compare(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ filename_trans_t *a = (filename_trans_t *)key1;
+ filename_trans_t *b = (filename_trans_t *)key2;
+
+ return a->stype != b->stype || a->ttype != b->ttype || a->tclass != b->tclass || strcmp(a->name, b->name);
+}
+
+static unsigned int range_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+ range_trans_t *k = (range_trans_t *)key;
+ return ((k->target_class + (k->target_type << 2) +
+ (k->source_type << 5)) & (h->size - 1));
+}
+
+static int range_trans_compare(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ range_trans_t *a = (range_trans_t *)key1;
+ range_trans_t *b = (range_trans_t *)key2;
+
+ return a->source_type != b->source_type || a->target_type != b->target_type || a->target_class != b->target_class;
+}
+
+static unsigned int role_trans_hash(hashtab_t h, hashtab_key_t key)
+{
+ role_trans_t *k = (role_trans_t *)key;
+ return ((k->role + (k->type << 2) +
+ (k->tclass << 5)) & (h->size - 1));
+}
+
+static int role_trans_compare(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ role_trans_t *a = (role_trans_t *)key1;
+ role_trans_t *b = (role_trans_t *)key2;
+
+ return a->role != b->role || a->type != b->type || a->tclass != b->tclass;
+}
+
+/* Based on MurmurHash3, written by Austin Appleby and placed in the
+ * public domain.
+ */
+static unsigned int avrulex_hash(__attribute__((unused)) hashtab_t h, hashtab_key_t key)
+{
+ avtab_key_t *k = (avtab_key_t *)key;
+
+ static const uint32_t c1 = 0xcc9e2d51;
+ static const uint32_t c2 = 0x1b873593;
+ static const uint32_t r1 = 15;
+ static const uint32_t r2 = 13;
+ static const uint32_t m = 5;
+ static const uint32_t n = 0xe6546b64;
+
+ uint32_t hash = 0;
+
+#define mix(input) { \
+ uint32_t v = input; \
+ v *= c1; \
+ v = (v << r1) | (v >> (32 - r1)); \
+ v *= c2; \
+ hash ^= v; \
+ hash = (hash << r2) | (hash >> (32 - r2)); \
+ hash = hash * m + n; \
+}
+
+ mix(k->target_class);
+ mix(k->target_type);
+ mix(k->source_type);
+ mix(k->specified);
+
+#undef mix
+
+ hash ^= hash >> 16;
+ hash *= 0x85ebca6b;
+ hash ^= hash >> 13;
+ hash *= 0xc2b2ae35;
+ hash ^= hash >> 16;
+
+ return hash & (AVRULEX_TABLE_SIZE - 1);
+}
+
+static int avrulex_compare(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ avtab_key_t *a = (avtab_key_t *)key1;
+ avtab_key_t *b = (avtab_key_t *)key2;
+
+ return a->source_type != b->source_type || a->target_type != b->target_type || a->target_class != b->target_class || a->specified != b->specified;
+}
+
+int cil_binary_create(const struct cil_db *db, sepol_policydb_t **policydb)
+{
+ int rc = SEPOL_ERR;
+ struct sepol_policydb *pdb = NULL;
+
+ rc = __cil_policydb_create(db, &pdb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_binary_create_allocated_pdb(db, pdb);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ *policydb = pdb;
+
+ return SEPOL_OK;
+
+exit:
+ sepol_policydb_free(pdb);
+
+ return rc;
+}
+
+static void __cil_destroy_sepol_class_perms(class_perm_node_t *curr)
+{
+ class_perm_node_t *next;
+
+ while (curr) {
+ next = curr->next;
+ free(curr);
+ curr = next;
+ }
+}
+
+static int __cil_rule_to_sepol_class_perms(policydb_t *pdb, struct cil_list *classperms, class_perm_node_t **sepol_class_perms)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *i;
+ cil_list_for_each(i, classperms) {
+ if (i->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = i->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ class_perm_node_t *cpn = NULL;
+ class_datum_t *sepol_class = NULL;
+ uint32_t data = 0;
+
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_perms_to_datum(cp->perms, sepol_class, &data);
+ if (rc != SEPOL_OK) goto exit;
+ if (data == 0) {
+ /* No permissions */
+ return SEPOL_OK;
+ }
+ cpn = cil_malloc(sizeof(class_perm_node_t));
+ cpn->tclass = sepol_class->s.value;
+ cpn->data = data;
+ cpn->next = *sepol_class_perms;
+ *sepol_class_perms = cpn;
+ } else { /* MAP */
+ struct cil_list_item *j = NULL;
+ cil_list_for_each(j, cp->perms) {
+ struct cil_perm *cmp = j->data;
+ rc = __cil_rule_to_sepol_class_perms(pdb, cmp->classperms, sepol_class_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = i->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = __cil_rule_to_sepol_class_perms(pdb, cp->classperms, sepol_class_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_permx_to_sepol_class_perms(policydb_t *pdb, struct cil_permissionx *permx, class_perm_node_t **sepol_class_perms)
+{
+ int rc = SEPOL_OK;
+ struct cil_list *class_list = NULL;
+ struct cil_list_item *c;
+ class_datum_t *sepol_obj = NULL;
+ class_perm_node_t *cpn;
+ uint32_t data = 0;
+ char *perm_str = NULL;
+
+ class_list = cil_expand_class(permx->obj);
+
+ cil_list_for_each(c, class_list) {
+ rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ switch (permx->kind) {
+ case CIL_PERMX_KIND_IOCTL:
+ perm_str = CIL_KEY_IOCTL;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = __perm_str_to_datum(perm_str, sepol_obj, &data);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cpn = cil_malloc(sizeof(*cpn));
+ cpn->tclass = sepol_obj->s.value;
+ cpn->data = data;
+ cpn->next = *sepol_class_perms;
+ *sepol_class_perms = cpn;
+ }
+
+exit:
+ cil_list_destroy(&class_list, CIL_FALSE);
+
+ return rc;
+}
+
+static void __cil_init_sepol_type_set(type_set_t *t)
+{
+ ebitmap_init(&t->types);
+ ebitmap_init(&t->negset);
+ t->flags = 0;
+}
+
+static int __cil_add_sepol_type(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *datum, ebitmap_t *map)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *n = datum->nodes->head->data;
+ type_datum_t *sepol_datum = NULL;
+
+ if (n->flavor == CIL_TYPEATTRIBUTE) {
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+ ebitmap_for_each_bit(attr->types, tnode, i) {
+ if (!ebitmap_get_bit(attr->types, i)) continue;
+ datum = DATUM(db->val_to_type[i]);
+ rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum);
+ if (rc != SEPOL_OK) goto exit;
+ ebitmap_set_bit(map, sepol_datum->s.value - 1, 1);
+ }
+ } else {
+ rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum);
+ if (rc != SEPOL_OK) goto exit;
+ ebitmap_set_bit(map, sepol_datum->s.value - 1, 1);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *node)
+{
+ avrule_t *avrule;
+ struct cil_tree_node *source_node;
+ char *source_path;
+ int is_cil;
+
+ avrule = cil_malloc(sizeof(avrule_t));
+ avrule->specified = kind;
+ avrule->flags = 0;
+ __cil_init_sepol_type_set(&avrule->stypes);
+ __cil_init_sepol_type_set(&avrule->ttypes);
+ avrule->perms = NULL;
+ avrule->line = node->line;
+
+ avrule->source_filename = NULL;
+ avrule->source_line = node->line;
+ source_node = cil_tree_get_next_path(node, &source_path, &is_cil);
+ if (source_node) {
+ avrule->source_filename = source_path;
+ if (!is_cil) {
+ avrule->source_line = node->hll_line;
+ }
+ }
+
+ avrule->next = NULL;
+ return avrule;
+}
+
+static void __cil_destroy_sepol_avrules(avrule_t *curr)
+{
+ avrule_t *next;
+
+ while (curr) {
+ next = curr->next;
+ ebitmap_destroy(&curr->stypes.types);
+ ebitmap_destroy(&curr->stypes.negset);
+ ebitmap_destroy(&curr->ttypes.types);
+ ebitmap_destroy(&curr->ttypes.negset);
+ __cil_destroy_sepol_class_perms(curr->perms);
+ free(curr);
+ curr = next;
+ }
+}
+
+static void __cil_print_parents(const char *pad, struct cil_tree_node *n)
+{
+ if (!n) return;
+
+ __cil_print_parents(pad, n->parent);
+
+ if (n->flavor != CIL_SRC_INFO) {
+ cil_tree_log(n, CIL_ERR,"%s%s", pad, cil_node_to_string(n));
+ }
+}
+
+static void __cil_print_classperm(struct cil_list *cp_list)
+{
+ struct cil_list_item *i1, *i2;
+
+ i1 = cp_list->head;
+ if (i1->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = i1->data;
+ cil_log(CIL_ERR,"(%s (", DATUM(cp->class)->fqn);
+ cil_list_for_each(i2, cp->perms) {
+ cil_log(CIL_ERR,"%s",DATUM(i2->data)->fqn);
+ if (i2 != cp->perms->tail) {
+ cil_log(CIL_ERR," ");
+ } else {
+ cil_log(CIL_ERR,"))");
+ }
+ }
+ } else {
+ struct cil_classperms_set *cp_set = i1->data;
+ cil_log(CIL_ERR,"%s", DATUM(cp_set->set)->fqn);
+ }
+}
+
+static void __cil_print_permissionx(struct cil_permissionx *px)
+{
+ char *kind_str = "";
+ char *expr_str;
+
+ switch (px->kind) {
+ case CIL_PERMX_KIND_IOCTL:
+ kind_str = CIL_KEY_IOCTL;
+ break;
+ default:
+ kind_str = "unknown";
+ break;
+ }
+
+ __cil_expr_to_string(px->expr_str, CIL_PERMISSIONX, &expr_str);
+
+ cil_log(CIL_ERR, "%s %s (%s)", kind_str, DATUM(px->obj)->fqn, expr_str);
+
+ free(expr_str);
+}
+
+static void __cil_print_rule(const char *pad, const char *kind, struct cil_avrule *avrule)
+{
+ cil_log(CIL_ERR,"%s(%s ", pad, kind);
+ cil_log(CIL_ERR,"%s %s ", DATUM(avrule->src)->fqn, DATUM(avrule->tgt)->fqn);
+
+ if (!avrule->is_extended) {
+ __cil_print_classperm(avrule->perms.classperms);
+ } else {
+ cil_log(CIL_ERR, "(");
+ __cil_print_permissionx(avrule->perms.x.permx);
+ cil_log(CIL_ERR, ")");
+ }
+
+ cil_log(CIL_ERR,")\n");
+}
+
+static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc;
+ struct cil_list_item *i2;
+ struct cil_list *matching;
+ struct cil_avrule *cil_rule = node->data;
+ struct cil_avrule target;
+ struct cil_tree_node *n2;
+ struct cil_avrule *r2;
+ char *neverallow_str;
+ char *allow_str;
+ enum cil_flavor avrule_flavor;
+
+ target.rule_kind = CIL_AVRULE_ALLOWED;
+ target.is_extended = cil_rule->is_extended;
+ target.src = cil_rule->src;
+ target.tgt = cil_rule->tgt;
+ target.perms = cil_rule->perms;
+
+ if (!cil_rule->is_extended) {
+ neverallow_str = CIL_KEY_NEVERALLOW;
+ allow_str = CIL_KEY_ALLOW;
+ avrule_flavor = CIL_AVRULE;
+ } else {
+ neverallow_str = CIL_KEY_NEVERALLOWX;
+ allow_str = CIL_KEY_ALLOWX;
+ avrule_flavor = CIL_AVRULEX;
+ }
+ cil_tree_log(node, CIL_ERR, "%s check failed", neverallow_str);
+ __cil_print_rule(" ", neverallow_str, cil_rule);
+ cil_list_init(&matching, CIL_NODE);
+ rc = cil_find_matching_avrule_in_ast(db->ast->root, avrule_flavor, &target, matching, CIL_FALSE);
+ if (rc) {
+ cil_log(CIL_ERR, "Error occurred while checking %s rules\n", neverallow_str);
+ cil_list_destroy(&matching, CIL_FALSE);
+ goto exit;
+ }
+
+ cil_list_for_each(i2, matching) {
+ n2 = i2->data;
+ r2 = n2->data;
+ __cil_print_parents(" ", n2);
+ __cil_print_rule(" ", allow_str, r2);
+ }
+ cil_log(CIL_ERR,"\n");
+ cil_list_destroy(&matching, CIL_FALSE);
+
+exit:
+ return rc;
+}
+
+static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct cil_tree_node *node, int *violation)
+{
+ int rc = SEPOL_OK;
+ struct cil_avrule *cil_rule = node->data;
+ struct cil_symtab_datum *tgt = cil_rule->tgt;
+ uint32_t kind;
+ avrule_t *rule;
+ struct cil_list *xperms = NULL;
+ struct cil_list_item *item;
+
+ if (!cil_rule->is_extended) {
+ kind = AVRULE_NEVERALLOW;
+ } else {
+ kind = AVRULE_XPERMS_NEVERALLOW;
+ }
+
+ rule = __cil_init_sepol_avrule(kind, node);
+ rule->next = NULL;
+
+ rc = __cil_add_sepol_type(pdb, db, cil_rule->src, &rule->stypes.types);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (tgt->fqn == CIL_KEY_SELF) {
+ rule->flags = RULE_SELF;
+ } else {
+ rc = __cil_add_sepol_type(pdb, db, cil_rule->tgt, &rule->ttypes.types);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (!cil_rule->is_extended) {
+ rc = __cil_rule_to_sepol_class_perms(pdb, cil_rule->perms.classperms, &rule->perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = check_assertion(pdb, rule);
+ if (rc == CIL_TRUE) {
+ *violation = CIL_TRUE;
+ rc = __cil_print_neverallow_failure(db, node);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ } else {
+ rc = __cil_permx_to_sepol_class_perms(pdb, cil_rule->perms.x.permx, &rule->perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->perms, &xperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_for_each(item, xperms) {
+ rule->xperms = item->data;
+ rc = check_assertion(pdb, rule);
+ if (rc == CIL_TRUE) {
+ *violation = CIL_TRUE;
+ rc = __cil_print_neverallow_failure(db, node);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ }
+
+exit:
+ if (xperms != NULL) {
+ cil_list_for_each(item, xperms) {
+ free(item->data);
+ item->data = NULL;
+ }
+ cil_list_destroy(&xperms, CIL_FALSE);
+ }
+
+ rule->xperms = NULL;
+ __cil_destroy_sepol_avrules(rule);
+
+ return rc;
+}
+
+static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struct cil_list *neverallows, int *violation)
+{
+ int rc = SEPOL_OK;
+ struct cil_list_item *item;
+
+ cil_list_for_each(item, neverallows) {
+ rc = cil_check_neverallow(db, pdb, item->data, violation);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+ struct cil_classperms *cp;
+ struct cil_list *cp_list;
+ class_datum_t *sepol_class = pdb->class_val_to_struct[class - 1];
+ unsigned i;
+
+ cil_classperms_init(&cp);
+
+ cp->class = class_value_to_cil[class];
+ if (!cp->class) goto exit;
+
+ cil_list_init(&cp->perms, CIL_PERM);
+ for (i = 0; i < sepol_class->permissions.nprim; i++) {
+ struct cil_perm *perm;
+ if ((data & (1 << i)) == 0) continue;
+ perm = perm_value_to_cil[class][i+1];
+ if (!perm) goto exit;
+ cil_list_append(cp->perms, CIL_PERM, perm);
+ }
+
+ cil_list_init(&cp_list, CIL_CLASSPERMS);
+ cil_list_append(cp_list, CIL_CLASSPERMS, cp);
+
+ return cp_list;
+
+exit:
+ cil_log(CIL_ERR,"Failed to create CIL class-permissions from sepol values\n");
+ return NULL;
+}
+
+static int cil_avrule_from_sepol(policydb_t *pdb, avtab_ptr_t sepol_rule, struct cil_avrule *cil_rule, void *type_value_to_cil[], struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[])
+{
+ int rc = SEPOL_ERR;
+ avtab_key_t *k = &sepol_rule->key;
+ avtab_datum_t *d = &sepol_rule->datum;
+ cil_rule->src = type_value_to_cil[k->source_type];
+ if (!cil_rule->src) goto exit;
+
+ cil_rule->tgt = type_value_to_cil[k->target_type];
+ if (!cil_rule->tgt) goto exit;
+
+ cil_rule->perms.classperms = cil_classperms_from_sepol(pdb, k->target_class, d->data, class_value_to_cil, perm_value_to_cil);
+ if (!cil_rule->perms.classperms) goto exit;
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR,"Failed to create CIL AV rule from sepol values\n");
+ return rc;
+}
+
+static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void *type_value_to_cil, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[], int *violation)
+{
+ int rc = SEPOL_OK;
+ int i;
+
+ for (i = 0; i < db->num_types; i++) {
+ type_datum_t *child;
+ type_datum_t *parent;
+ avtab_ptr_t bad = NULL;
+ int numbad = 0;
+ struct cil_type *t = db->val_to_type[i];
+
+ if (!t->bounds) continue;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(t), &child);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = __cil_get_sepol_type_datum(pdb, DATUM(t->bounds), &parent);
+ if (rc != SEPOL_OK) goto exit;
+
+ rc = bounds_check_type(NULL, pdb, child->s.value, parent->s.value, &bad, &numbad);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (bad) {
+ avtab_ptr_t cur;
+ struct cil_avrule target;
+ struct cil_tree_node *n1 = NULL;
+
+ *violation = CIL_TRUE;
+
+ target.is_extended = 0;
+ target.rule_kind = CIL_AVRULE_ALLOWED;
+ target.src_str = NULL;
+ target.tgt_str = NULL;
+
+ cil_log(CIL_ERR, "Child type %s exceeds bounds of parent %s\n",
+ t->datum.fqn, t->bounds->datum.fqn);
+ for (cur = bad; cur; cur = cur->next) {
+ struct cil_list_item *i2;
+ struct cil_list *matching;
+
+ rc = cil_avrule_from_sepol(pdb, cur, &target, type_value_to_cil, class_value_to_cil, perm_value_to_cil);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to convert sepol avrule to CIL\n");
+ goto exit;
+ }
+ __cil_print_rule(" ", "allow", &target);
+ cil_list_init(&matching, CIL_NODE);
+ rc = cil_find_matching_avrule_in_ast(db->ast->root, CIL_AVRULE, &target, matching, CIL_TRUE);
+ if (rc) {
+ cil_log(CIL_ERR, "Error occurred while checking type bounds\n");
+ cil_list_destroy(&matching, CIL_FALSE);
+ cil_list_destroy(&target.perms.classperms, CIL_TRUE);
+ bounds_destroy_bad(bad);
+ goto exit;
+ }
+ cil_list_for_each(i2, matching) {
+ struct cil_tree_node *n2 = i2->data;
+ struct cil_avrule *r2 = n2->data;
+ if (n1 == n2) {
+ cil_log(CIL_ERR, " <See previous>\n");
+ } else {
+ n1 = n2;
+ __cil_print_parents(" ", n2);
+ __cil_print_rule(" ", "allow", r2);
+ }
+ }
+ cil_list_destroy(&matching, CIL_FALSE);
+ cil_list_destroy(&target.perms.classperms, CIL_TRUE);
+ }
+ bounds_destroy_bad(bad);
+ }
+ }
+
+exit:
+ return rc;
+}
+
+// assumes policydb is already allocated and initialized properly with things
+// like policy type set to kernel and version set appropriately
+int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *policydb)
+{
+ int rc = SEPOL_ERR;
+ int i;
+ struct cil_args_binary extra_args;
+ policydb_t *pdb = &policydb->p;
+ struct cil_list *neverallows = NULL;
+ hashtab_t filename_trans_table = NULL;
+ hashtab_t range_trans_table = NULL;
+ hashtab_t role_trans_table = NULL;
+ hashtab_t avrulex_ioctl_table = NULL;
+ void **type_value_to_cil = NULL;
+ struct cil_class **class_value_to_cil = NULL;
+ struct cil_perm ***perm_value_to_cil = NULL;
+
+ if (db == NULL || policydb == NULL) {
+ if (db == NULL) {
+ cil_log(CIL_ERR,"db == NULL\n");
+ } else if (policydb == NULL) {
+ cil_log(CIL_ERR,"policydb == NULL\n");
+ }
+ return SEPOL_ERR;
+ }
+
+ /* libsepol values start at 1. Just allocate extra memory rather than
+ * subtract 1 from the sepol value.
+ */
+ type_value_to_cil = calloc(db->num_types_and_attrs+1, sizeof(*type_value_to_cil));
+ if (!type_value_to_cil) goto exit;
+
+ class_value_to_cil = calloc(db->num_classes+1, sizeof(*class_value_to_cil));
+ if (!class_value_to_cil) goto exit;
+
+ perm_value_to_cil = calloc(db->num_classes+1, sizeof(*perm_value_to_cil));
+ if (!perm_value_to_cil) goto exit;
+ for (i=1; i < db->num_classes+1; i++) {
+ perm_value_to_cil[i] = calloc(PERMS_PER_CLASS+1, sizeof(*perm_value_to_cil[i]));
+ if (!perm_value_to_cil[i]) goto exit;
+ }
+
+ rc = __cil_policydb_init(pdb, db, class_value_to_cil, perm_value_to_cil);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR,"Problem in policydb_init\n");
+ goto exit;
+ }
+
+ filename_trans_table = hashtab_create(filename_trans_hash, filename_trans_compare, FILENAME_TRANS_TABLE_SIZE);
+ if (!filename_trans_table) {
+ cil_log(CIL_INFO, "Failure to create hashtab for filename_trans\n");
+ goto exit;
+ }
+
+ range_trans_table = hashtab_create(range_trans_hash, range_trans_compare, RANGE_TRANS_TABLE_SIZE);
+ if (!range_trans_table) {
+ cil_log(CIL_INFO, "Failure to create hashtab for range_trans\n");
+ goto exit;
+ }
+
+ role_trans_table = hashtab_create(role_trans_hash, role_trans_compare, ROLE_TRANS_TABLE_SIZE);
+ if (!role_trans_table) {
+ cil_log(CIL_INFO, "Failure to create hashtab for role_trans\n");
+ goto exit;
+ }
+
+ avrulex_ioctl_table = hashtab_create(avrulex_hash, avrulex_compare, AVRULEX_TABLE_SIZE);
+ if (!avrulex_ioctl_table) {
+ cil_log(CIL_INFO, "Failure to create hashtab for avrulex\n");
+ goto exit;
+ }
+
+ cil_list_init(&neverallows, CIL_LIST_ITEM);
+
+ extra_args.db = db;
+ extra_args.pdb = pdb;
+ extra_args.neverallows = neverallows;
+ extra_args.filename_trans_table = filename_trans_table;
+ extra_args.range_trans_table = range_trans_table;
+ extra_args.role_trans_table = role_trans_table;
+ extra_args.avrulex_ioctl_table = avrulex_ioctl_table;
+ extra_args.type_value_to_cil = type_value_to_cil;
+
+ for (i = 1; i <= 3; i++) {
+ extra_args.pass = i;
+
+ rc = cil_tree_walk(db->ast->root, __cil_binary_create_helper, NULL, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure while walking cil database\n");
+ goto exit;
+ }
+
+ if (i == 1) {
+ rc = __cil_policydb_val_arrays_create(pdb);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure creating val_to_{struct,name} arrays\n");
+ goto exit;
+ }
+ }
+
+ if (i == 3) {
+ rc = hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_to_policydb, pdb);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure creating avrulex rules\n");
+ goto exit;
+ }
+ }
+ }
+
+ rc = cil_sidorder_to_policydb(pdb, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_contexts_to_policydb(pdb, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure while inserting cil contexts into sepol policydb\n");
+ goto exit;
+ }
+
+ if (pdb->type_attr_map == NULL) {
+ rc = __cil_typeattr_bitmap_init(pdb);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure while initializing typeattribute bitmap\n");
+ goto exit;
+ }
+ }
+
+ cond_optimize_lists(pdb->cond_list);
+ __cil_set_conditional_state_and_flags(pdb);
+
+ if (db->disable_neverallow != CIL_TRUE) {
+ int violation = CIL_FALSE;
+ cil_log(CIL_INFO, "Checking Neverallows\n");
+ rc = cil_check_neverallows(db, pdb, neverallows, &violation);
+ if (rc != SEPOL_OK) goto exit;
+
+ cil_log(CIL_INFO, "Checking User Bounds\n");
+ rc = bounds_check_users(NULL, pdb);
+ if (rc) {
+ violation = CIL_TRUE;
+ }
+
+ cil_log(CIL_INFO, "Checking Role Bounds\n");
+ rc = bounds_check_roles(NULL, pdb);
+ if (rc) {
+ violation = CIL_TRUE;
+ }
+
+ cil_log(CIL_INFO, "Checking Type Bounds\n");
+ rc = cil_check_type_bounds(db, pdb, type_value_to_cil, class_value_to_cil, perm_value_to_cil, &violation);
+ if (rc != SEPOL_OK) goto exit;
+
+ if (violation == CIL_TRUE) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ hashtab_destroy(filename_trans_table);
+ hashtab_destroy(range_trans_table);
+ hashtab_destroy(role_trans_table);
+ hashtab_destroy(avrulex_ioctl_table);
+ free(type_value_to_cil);
+ free(class_value_to_cil);
+ /* Range is because libsepol values start at 1. */
+ for (i=1; i < db->num_classes+1; i++) {
+ free(perm_value_to_cil[i]);
+ }
+ free(perm_value_to_cil);
+ cil_list_destroy(&neverallows, CIL_FALSE);
+
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_binary.h b/libsepol/cil/src/cil_binary.h
new file mode 100644
index 0000000..c59b1e3
--- /dev/null
+++ b/libsepol/cil/src/cil_binary.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef _CIL_BINARY_H_
+#define _CIL_BINARY_H_
+
+#include <sepol/policydb/policydb.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+/**
+ * Create a binary policydb from the cil db.
+ *
+ * @param[in] db The cil database.
+ * @param[in] pdb The policy database.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_binary_create(const struct cil_db *db, sepol_policydb_t **pdb);
+
+/**
+ * Create a pre allocated binary policydb from the cil db.
+ *
+ * It is assumed that pdb has been allocated and initialzed so that fields such
+ * as policy type and version are set appropriately. It is reccomended that
+ * instead of calling this, one instead calls cil_binary_create, which will
+ * properly allocate and initialize the pdb and then calls this function. This
+ * funcion is used to maintain binary backwards compatability.
+ *
+ * @param[in] db The cil database.
+ * @param[in] pdb The policy database.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *pdb);
+
+/**
+ * Insert cil common structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the common into.
+ * @param[in] datum The cil_common datum.
+ * @param[out] common_out The sepol common to send back.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out);
+
+/**
+ * Insert cil class structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the class into.
+ * @param[in] datum The cil_class datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_class_to_policydb(policydb_t *pdb, struct cil_class *cil_class);
+
+/**
+ * Insert cil role structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role into.
+ * @param[in] datum The cil_role datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role);
+
+/**
+ * Insert cil roletype structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the roletype into.
+ * @param[in] db The cil database
+ * @param[in] datum The cil_roletype datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR otherwise.
+ */
+int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role);
+
+/**
+ * Insert cil type structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the type into.
+ * @param[in] datum The cil_type datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]);
+
+/**
+ * Insert cil typealias structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the typealias into.
+ * @param[in] datum The cil_typealias datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
+
+/**
+ * Insert cil typepermissive structure into sepol policydb.
+ * The function looks up the perviously inserted type and flips the bit
+ * in the permssive types bitmap that corresponds to that type's value.
+ *
+ * @param[in] pdb The policy database to insert the typepermissive into.
+ * @param[in] datum The cil_typepermissive datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm);
+
+/**
+ * Insert cil attribute structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the attribute into.
+ * @param[in] datum The cil_attribute datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]);
+
+/**
+ * Insert cil attribute structure into sepol type->attribute bitmap.
+ * The function calls helper functions to loop over the attributes lists
+ * of types and negative types. If either of the lists contain an attribute,
+ * the helper functions will recurse into the attribute and record the
+ * attribute's types and negative types. There is no minimum depth.
+ *
+ * @param[in] pdb The policy database that contains the type->attribute bitmap.
+ * @param[in] db The cil database
+ * @param[in] node The tree node that contains the cil_attribute.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *cdb, struct cil_typeattribute *cil_attr);
+
+/**
+ * Insert cil policycap structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the policycap into.
+ * @param[in] node The tree node that contains the cil_policycap.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap);
+
+/**
+ * Insert cil user structure into sepol policydb.
+ *
+ * @param[in] pdb THe policy database to insert the user into.
+ * @param[in] node The tree node that contains the cil_user.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user);
+
+/**
+ * Insert cil userrole structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the userrole into.
+ * @param[in] db The cil database
+ * @param[in] datum The cil_user
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR otherwise.
+ */
+int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user);
+
+/**
+ * Insert cil bool structure into sepol policydb.
+ *
+ * @param[in] pdb THe policy database to insert the bool into.
+ * @param[in] datum The cil_bool datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool);
+
+/**
+ * Insert all ordered cil category structures into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the categories into.
+ * @param[in] db The cil database that contains the category order list.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
+
+/**
+ * Insert cil category alias structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the category alias into.
+ * @param[in] datum The cil_catalias datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
+
+/**
+ * Insert the cil sensitivityorder into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the sensitivityorder into.
+ * @param[in] db the cil database that contains the sensitivityorder list.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
+
+/**
+ * Insert cil type rule structure into sepol policydb. This includes
+ * typetransition, typechange, and typemember.
+ *
+ * @param[in] pdb The policy database to insert the type rule into.
+ * @param[in] datum The cil_type_rule datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule);
+
+/**
+ * Insert cil avrule structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the avrule into.
+ * @param[in] datum The cil_avrule datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule);
+
+/**
+ * Insert cil booleanif structure into sepol policydb. This populates the
+ * policydb conditional list. Each conditional node contains an expression
+ * and true/false avtab_ptr lists that point into te_cond_avtab.
+ *
+ * @param[in] pdb The policy database to insert the booleanif into.
+ * @param[in] node The cil_booleanif node.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table);
+
+/**
+ * Insert cil role transition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role transition into.
+ * @param[in] datum The cil_role_trans datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table);
+
+/**
+ * Insert cil role allow structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the role allow into.
+ * @param[in] datum The cil_role_allow datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow);
+
+/**
+ * Insert cil file transition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the file transition into.
+ * @param[in] datum The cil_nametypetransition datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, hashtab_t filename_trans_table);
+
+/**
+ * Insert cil constrain/mlsconstrain structure(s) into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the (mls)constrain into.
+ * @param[in] datum The cil_(mls)constrain datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain);
+
+/**
+ * Define sepol level.
+ * Associates the sepol level (sensitivity) with categories.
+ * Looks at the cil_sens structure for a list of cil_cats to
+ * associate the sensitivity with.
+ * Sets the sepol level as defined in the sepol policy database.
+ *
+ * @param[in] pdb The policy database that holds the sepol level.
+ * @param[in] datum The cil_sens datum.
+ *
+ * @return SEPOL_OK upon success or SEPOL_ERR upon error.
+ */
+int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens);
+
+/**
+ * Insert cil rangetransition structure into sepol policydb.
+ *
+ * @param[in] pdb The policy database to insert the rangetransition into.
+ * @param[in] datum The cil_rangetransition datum.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans, hashtab_t range_trans_table);
+
+/**
+ * Insert cil portcon structure into sepol policydb.
+ * The function is given a structure containing the sorted portcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the portcon into.
+ * @param[in] node The cil_sort structure that contains the sorted portcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons);
+
+/**
+ * Insert cil netifcon structure into sepol policydb.
+ * The function is given a structure containing the sorted netifcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the netifcon into.
+ * @param[in] node The cil_sort structure that contains the sorted netifcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons);
+
+/**
+ * Insert cil nodecon structure into sepol policydb.
+ * The function is given a structure containing the sorted nodecons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the nodecon into.
+ * @param[in] node The cil_sort structure that contains the sorted nodecons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons);
+
+/**
+ * Insert cil fsuse structure into sepol policydb.
+ * The function is given a structure containing the sorted fsuses and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the fsuse into.
+ * @param[in] node The cil_sort structure that contains the sorted fsuses.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses);
+
+/**
+ * Insert cil genfscon structure into sepol policydb.
+ * The function is given a structure containing the sorted genfscons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the genfscon into.
+ * @param[in] node The cil_sort structure that contains the sorted genfscons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons);
+
+/**
+ * Insert cil pirqcon structure into sepol policydb.
+ * The function is given a structure containing the sorted pirqcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the pirqcon into.
+ * @param[in] node The cil_sort structure that contains the sorted pirqcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons);
+
+/**
+ * Insert cil iomemcon structure into sepol policydb.
+ * The function is given a structure containing the sorted iomemcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the iomemcon into.
+ * @param[in] node The cil_sort structure that contains the sorted iomemcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons);
+
+/**
+ * Insert cil ioportcon structure into sepol policydb.
+ * The function is given a structure containing the sorted ioportcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the ioportcon into.
+ * @param[in] node The cil_sort structure that contains the sorted ioportcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons);
+
+/**
+ * Insert cil pcidevicecon structure into sepol policydb.
+ * The function is given a structure containing the sorted pcidevicecons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the pcidevicecon into.
+ * @param[in] node The cil_sort structure that contains the sorted pcidevicecons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons);
+
+/**
+ * Create an mls level using a cil level.
+ * The function is given a structure containing the a cil_level and
+ * outputs a created mls_level_t.
+ *
+ * @param[in] pdb The policy database to use to get sepol level from cil_level's sensitivity.
+ * @param[in] cil_level The cil_level that will be used to create an mls_level_t.
+ * @param[out] mls_level The mls_level that is created.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level);
+
+#endif //_CIL_BINARY_H_
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
new file mode 100644
index 0000000..1505873
--- /dev/null
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -0,0 +1,6297 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_parser.h"
+#include "cil_build_ast.h"
+#include "cil_copy_ast.h"
+#include "cil_verify.h"
+#include "cil_strpool.h"
+
+struct cil_args_build {
+ struct cil_tree_node *ast;
+ struct cil_db *db;
+ struct cil_tree_node *macro;
+ struct cil_tree_node *boolif;
+ struct cil_tree_node *tunif;
+ struct cil_tree_node *in;
+};
+
+int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *curr;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_N_STRINGS,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ rc = __cil_verify_syntax(current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_init(list, flavor);
+
+ for (curr = current; curr != NULL; curr = curr->next) {
+ cil_list_append(*list, CIL_STRING, curr->data);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_gen_node(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor)
+{
+ int rc = SEPOL_ERR;
+ symtab_t *symtab = NULL;
+
+ rc = __cil_verify_name((const char*)key);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_get_symtab(ast_node->parent, &symtab, sflavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = datum;
+ ast_node->flavor = nflavor;
+
+ if (symtab != NULL) {
+ rc = cil_symtab_insert(symtab, (hashtab_key_t)key, datum, ast_node);
+ if (rc == SEPOL_EEXIST) {
+ cil_log(CIL_ERR, "Re-declaration of %s %s\n",
+ cil_node_to_string(ast_node), key);
+ if (cil_symtab_get_datum(symtab, key, &datum) == SEPOL_OK) {
+ if (sflavor == CIL_SYM_BLOCKS) {
+ struct cil_tree_node *node = datum->nodes->head->data;
+ cil_tree_log(node, CIL_ERR, "Previous declaration");
+ }
+ }
+ goto exit;
+ }
+ }
+
+ if (ast_node->flavor >= CIL_MIN_DECLARATIVE && ast_node->parent->flavor == CIL_MACRO) {
+ struct cil_list_item *item;
+ struct cil_list *param_list = ((struct cil_macro*)ast_node->parent->data)->params;
+ if (param_list != NULL) {
+ cil_list_for_each(item, param_list) {
+ struct cil_param *param = item->data;
+ if (param->flavor == ast_node->flavor) {
+ if (param->str == key) {
+ cil_log(CIL_ERR, "%s %s shadows a macro parameter in macro declaration\n", cil_node_to_string(ast_node), key);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to create node\n");
+ return rc;
+}
+
+void cil_clear_node(struct cil_tree_node *ast_node)
+{
+ if (ast_node == NULL) {
+ return;
+ }
+
+ ast_node->data = NULL;
+ ast_node->flavor = CIL_NONE;
+}
+
+int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_N_LISTS | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_block *block = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_block_init(&block);
+
+ block->is_abstract = is_abstract;
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)block, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_BLOCK);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad block declaration");
+ cil_destroy_block(block);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_block(struct cil_block *block)
+{
+ if (block == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&block->datum);
+ cil_symtab_array_destroy(block->symtab);
+ cil_list_destroy(&block->bi_nodes, CIL_FALSE);
+
+ free(block);
+}
+
+int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_blockinherit *inherit = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_blockinherit_init(&inherit);
+
+ inherit->block_str = parse_current->next->data;
+
+ ast_node->data = inherit;
+ ast_node->flavor = CIL_BLOCKINHERIT;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad blockinherit declaration");
+ cil_destroy_blockinherit(inherit);
+ return rc;
+}
+
+void cil_destroy_blockinherit(struct cil_blockinherit *inherit)
+{
+ if (inherit == NULL) {
+ return;
+ }
+
+ free(inherit);
+}
+
+int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_blockabstract *abstract = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_blockabstract_init(&abstract);
+
+ abstract->block_str = parse_current->next->data;
+
+ ast_node->data = abstract;
+ ast_node->flavor = CIL_BLOCKABSTRACT;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad blockabstract declaration");
+ cil_destroy_blockabstract(abstract);
+ return rc;
+}
+
+void cil_destroy_blockabstract(struct cil_blockabstract *abstract)
+{
+ if (abstract == NULL) {
+ return;
+ }
+
+ free(abstract);
+}
+
+int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_N_LISTS,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_in *in = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_in_init(&in);
+
+ in->block_str = parse_current->next->data;
+
+ ast_node->data = in;
+ ast_node->flavor = CIL_IN;
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad in statement");
+ cil_destroy_in(in);
+ return rc;
+}
+
+void cil_destroy_in(struct cil_in *in)
+{
+ if (in == NULL) {
+ return;
+ }
+
+ cil_symtab_array_destroy(in->symtab);
+
+ free(in);
+}
+
+int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_class *class = NULL;
+ struct cil_tree_node *perms = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_class_init(&class);
+
+ key = parse_current->next->data;
+ if (key == CIL_KEY_UNORDERED) {
+ cil_log(CIL_ERR, "'unordered' keyword is reserved and not a valid class name.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)class, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_CLASS);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->next != NULL) {
+ perms = parse_current->next->next->cl_head;
+ rc = cil_gen_perm_nodes(db, perms, ast_node, CIL_PERM, &class->num_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad class declaration");
+ cil_destroy_class(class);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_class(struct cil_class *class)
+{
+ if (class == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&class->datum);
+ cil_symtab_destroy(&class->perms);
+
+ free(class);
+}
+
+int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_classorder *classorder = NULL;
+ struct cil_list_item *curr = NULL;
+ struct cil_list_item *head = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classorder_init(&classorder);
+
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASSORDER, &classorder->class_list_str);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ head = classorder->class_list_str->head;
+ cil_list_for_each(curr, classorder->class_list_str) {
+ if (curr->data == CIL_KEY_UNORDERED) {
+ if (curr == head && curr->next == NULL) {
+ cil_log(CIL_ERR, "Classorder 'unordered' keyword must be followed by one or more class.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ } else if (curr != head) {
+ cil_log(CIL_ERR, "Classorder can only use 'unordered' keyword as the first item in the list.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ ast_node->data = classorder;
+ ast_node->flavor = CIL_CLASSORDER;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad classorder declaration");
+ cil_destroy_classorder(classorder);
+ return rc;
+}
+
+void cil_destroy_classorder(struct cil_classorder *classorder)
+{
+ if (classorder == NULL) {
+ return;
+ }
+
+ if (classorder->class_list_str != NULL) {
+ cil_list_destroy(&classorder->class_list_str, 1);
+ }
+
+ free(classorder);
+}
+
+int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
+{
+ char *key = NULL;
+ struct cil_perm *perm = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_perm_init(&perm);
+
+ key = parse_current->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)perm, (hashtab_key_t)key, CIL_SYM_PERMS, flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ perm->value = *num_perms;
+ (*num_perms)++;
+
+ return SEPOL_OK;
+
+exit:
+ cil_destroy_perm(perm);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_perm(struct cil_perm *perm)
+{
+ if (perm == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&perm->datum);
+ cil_list_destroy(&perm->classperms, CIL_FALSE);
+
+ free(perm);
+}
+
+int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *new_ast = NULL;
+
+ while(current_perm != NULL) {
+ if (current_perm->cl_head != NULL) {
+
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ cil_tree_node_init(&new_ast);
+ new_ast->parent = ast_node;
+ new_ast->line = current_perm->line;
+ new_ast->hll_line = current_perm->hll_line;
+
+ rc = cil_gen_perm(db, current_perm, new_ast, flavor, num_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (ast_node->cl_head == NULL) {
+ ast_node->cl_head = new_ast;
+ } else {
+ ast_node->cl_tail->next = new_ast;
+ }
+ ast_node->cl_tail = new_ast;
+
+ current_perm = current_perm->next;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad permissions\n");
+ return rc;
+}
+
+int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perms)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_N_STRINGS | CIL_SYN_N_LISTS,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ rc = __cil_verify_syntax(start_perm->cl_head, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_expr(start_perm, CIL_PERM, perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad permission list or expression\n");
+ return rc;
+}
+
+int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classperms_init(cp);
+
+ (*cp)->class_str = parse_current->data;
+
+ rc = cil_fill_perms(parse_current->next, &(*cp)->perm_strs);
+ if (rc != SEPOL_OK) {
+ cil_destroy_classperms(*cp);
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad class-permissions\n");
+ *cp = NULL;
+ return rc;
+}
+
+void cil_destroy_classperms(struct cil_classperms *cp)
+{
+ if (cp == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&cp->perm_strs, CIL_TRUE);
+ cil_list_destroy(&cp->perms, CIL_FALSE);
+
+ free(cp);
+}
+
+void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set)
+{
+ cil_classperms_set_init(cp_set);
+ (*cp_set)->set_str = parse_current->data;
+}
+
+void cil_destroy_classperms_set(struct cil_classperms_set *cp_set)
+{
+ if (cp_set == NULL) {
+ return;
+ }
+
+ free(cp_set);
+}
+
+int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **cp_list)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *curr;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ if (parse_current == NULL || cp_list == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_init(cp_list, CIL_CLASSPERMS);
+
+ curr = parse_current->cl_head;
+
+ if (curr == NULL) {
+ /* Class-perms form: SET1 */
+ struct cil_classperms_set *new_cp_set;
+ cil_fill_classperms_set(parse_current, &new_cp_set);
+ cil_list_append(*cp_list, CIL_CLASSPERMS_SET, new_cp_set);
+ } else if (curr->cl_head == NULL) {
+ /* Class-perms form: (CLASS1 (PERM1 ...)) */
+ struct cil_classperms *new_cp;
+ rc = cil_fill_classperms(curr, &new_cp);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_append(*cp_list, CIL_CLASSPERMS, new_cp);
+ } else {
+ cil_log(CIL_ERR, "Bad class-permissions list syntax\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Problem filling class-permissions list\n");
+ cil_list_destroy(cp_list, CIL_TRUE);
+ return rc;
+}
+
+void cil_destroy_classperms_list(struct cil_list **cp_list)
+{
+ struct cil_list_item *curr;
+
+ if (cp_list == NULL || *cp_list == NULL) {
+ return;
+ }
+
+ cil_list_for_each(curr, *cp_list) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ cil_destroy_classperms(curr->data);
+ } else {
+ cil_destroy_classperms_set(curr->data);
+ }
+ }
+
+ cil_list_destroy(cp_list, CIL_FALSE);
+}
+
+int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ struct cil_classpermission *cp = NULL;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classpermission_init(&cp);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)cp, (hashtab_key_t)key, CIL_SYM_CLASSPERMSETS, CIL_CLASSPERMISSION);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad classpermission declaration");
+ cil_destroy_classpermission(cp);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_classpermission(struct cil_classpermission *cp)
+{
+ if (cp == NULL) {
+ return;
+ }
+
+ if (cp->datum.name != NULL) {
+ cil_list_destroy(&cp->classperms, CIL_FALSE);
+ } else {
+ /* anonymous classpermission from call */
+ cil_destroy_classperms_list(&cp->classperms);
+ }
+
+ cil_symtab_datum_destroy(&cp->datum);
+
+
+ free(cp);
+}
+
+int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_classpermissionset *cps = NULL;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classpermissionset_init(&cps);
+
+ cps->set_str = parse_current->next->data;
+
+ rc = cil_fill_classperms_list(parse_current->next->next, &cps->classperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = cps;
+ ast_node->flavor = CIL_CLASSPERMISSIONSET;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad classpermissionset");
+ cil_destroy_classpermissionset(cps);
+ return rc;
+}
+
+void cil_destroy_classpermissionset(struct cil_classpermissionset *cps)
+{
+ if (cps == NULL) {
+ return;
+ }
+
+ cil_destroy_classperms_list(&cps->classperms);
+
+ free(cps);
+}
+
+int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_class *map = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_class_init(&map);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)map, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_MAP_CLASS);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_MAP_PERM, &map->num_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad map class declaration");
+ cil_destroy_class(map);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_classmapping *mapping = NULL;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classmapping_init(&mapping);
+
+ mapping->map_class_str = parse_current->next->data;
+ mapping->map_perm_str = parse_current->next->next->data;
+
+ rc = cil_fill_classperms_list(parse_current->next->next->next, &mapping->classperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = mapping;
+ ast_node->flavor = CIL_CLASSMAPPING;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad classmapping declaration");
+ cil_destroy_classmapping(mapping);
+ return rc;
+}
+
+void cil_destroy_classmapping(struct cil_classmapping *mapping)
+{
+ if (mapping == NULL) {
+ return;
+ }
+
+ cil_destroy_classperms_list(&mapping->classperms);
+
+ free(mapping);
+}
+
+// TODO try to merge some of this with cil_gen_class (helper function for both)
+int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_class *common = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_class_init(&common);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)common, (hashtab_key_t)key, CIL_SYM_COMMONS, CIL_COMMON);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_PERM, &common->num_perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad common declaration");
+ cil_destroy_class(common);
+ cil_clear_node(ast_node);
+ return rc;
+
+}
+
+int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_classcommon *clscom = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_classcommon_init(&clscom);
+
+ clscom->class_str = parse_current->next->data;
+ clscom->common_str = parse_current->next->next->data;
+
+ ast_node->data = clscom;
+ ast_node->flavor = CIL_CLASSCOMMON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad classcommon declaration");
+ cil_destroy_classcommon(clscom);
+ return rc;
+
+}
+
+void cil_destroy_classcommon(struct cil_classcommon *clscom)
+{
+ if (clscom == NULL) {
+ return;
+ }
+
+ free(clscom);
+}
+
+int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_sid *sid = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_sid_init(&sid);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sid, (hashtab_key_t)key, CIL_SYM_SIDS, CIL_SID);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sid declaration");
+ cil_destroy_sid(sid);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_sid(struct cil_sid *sid)
+{
+ if (sid == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&sid->datum);
+ free(sid);
+}
+
+int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_sidcontext *sidcon = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_sidcontext_init(&sidcon);
+
+ sidcon->sid_str = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ sidcon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&sidcon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, sidcon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = sidcon;
+ ast_node->flavor = CIL_SIDCONTEXT;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sidcontext declaration");
+ cil_destroy_sidcontext(sidcon);
+ return rc;
+}
+
+void cil_destroy_sidcontext(struct cil_sidcontext *sidcon)
+{
+ if (sidcon == NULL) {
+ return;
+ }
+
+ if (sidcon->context_str == NULL && sidcon->context != NULL) {
+ cil_destroy_context(sidcon->context);
+ }
+
+ free(sidcon);
+}
+
+int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_sidorder *sidorder = NULL;
+ struct cil_list_item *curr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_sidorder_init(&sidorder);
+
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_SIDORDER, &sidorder->sid_list_str);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_for_each(curr, sidorder->sid_list_str) {
+ if (curr->data == CIL_KEY_UNORDERED) {
+ cil_log(CIL_ERR, "Sidorder cannot be unordered.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ ast_node->data = sidorder;
+ ast_node->flavor = CIL_SIDORDER;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sidorder declaration");
+ cil_destroy_sidorder(sidorder);
+ return rc;
+}
+
+void cil_destroy_sidorder(struct cil_sidorder *sidorder)
+{
+ if (sidorder == NULL) {
+ return;
+ }
+
+ if (sidorder->sid_list_str != NULL) {
+ cil_list_destroy(&sidorder->sid_list_str, 1);
+ }
+
+ free(sidorder);
+}
+
+int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_user *user = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_user_init(&user);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)user, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USER);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad user declaration");
+ cil_destroy_user(user);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_user(struct cil_user *user)
+{
+ if (user == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&user->datum);
+ ebitmap_destroy(user->roles);
+ free(user->roles);
+ free(user);
+}
+
+int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_userattribute *attr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userattribute_init(&attr);
+
+ key = parse_current->next->data;
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USERATTRIBUTE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userattribute declaration");
+ cil_destroy_userattribute(attr);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_userattribute(struct cil_userattribute *attr)
+{
+ struct cil_list_item *expr = NULL;
+ struct cil_list_item *next = NULL;
+
+ if (attr == NULL) {
+ return;
+ }
+
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ expr = attr->expr_list->head;
+ while (expr != NULL) {
+ next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+
+ cil_symtab_datum_destroy(&attr->datum);
+ ebitmap_destroy(attr->users);
+ free(attr->users);
+ free(attr);
+}
+
+int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_userattributeset *attrset = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userattributeset_init(&attrset);
+
+ attrset->attr_str = parse_current->next->data;
+
+ rc = cil_gen_expr(parse_current->next->next, CIL_USER, &attrset->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ ast_node->data = attrset;
+ ast_node->flavor = CIL_USERATTRIBUTESET;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userattributeset declaration");
+ cil_destroy_userattributeset(attrset);
+
+ return rc;
+}
+
+void cil_destroy_userattributeset(struct cil_userattributeset *attrset)
+{
+ if (attrset == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+ cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+ free(attrset);
+}
+
+int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_userlevel *usrlvl = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userlevel_init(&usrlvl);
+
+ usrlvl->user_str = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ usrlvl->level_str = parse_current->next->next->data;
+ } else {
+ cil_level_init(&usrlvl->level);
+
+ rc = cil_fill_level(parse_current->next->next->cl_head, usrlvl->level);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = usrlvl;
+ ast_node->flavor = CIL_USERLEVEL;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userlevel declaration");
+ cil_destroy_userlevel(usrlvl);
+ return rc;
+}
+
+void cil_destroy_userlevel(struct cil_userlevel *usrlvl)
+{
+ if (usrlvl == NULL) {
+ return;
+ }
+
+ if (usrlvl->level_str == NULL && usrlvl->level != NULL) {
+ cil_destroy_level(usrlvl->level);
+ }
+
+ free(usrlvl);
+}
+
+int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_userrange *userrange = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userrange_init(&userrange);
+
+ userrange->user_str = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ userrange->range_str = parse_current->next->next->data;
+ } else {
+ cil_levelrange_init(&userrange->range);
+
+ rc = cil_fill_levelrange(parse_current->next->next->cl_head, userrange->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = userrange;
+ ast_node->flavor = CIL_USERRANGE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userrange declaration");
+ cil_destroy_userrange(userrange);
+ return rc;
+}
+
+void cil_destroy_userrange(struct cil_userrange *userrange)
+{
+ if (userrange == NULL) {
+ return;
+ }
+
+ if (userrange->range_str == NULL && userrange->range != NULL) {
+ cil_destroy_levelrange(userrange->range);
+ }
+
+ free(userrange);
+}
+
+int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_userprefix *userprefix = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userprefix_init(&userprefix);
+
+ userprefix->user_str = parse_current->next->data;
+ userprefix->prefix_str = parse_current->next->next->data;
+
+ ast_node->data = userprefix;
+ ast_node->flavor = CIL_USERPREFIX;
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userprefix declaration");
+ cil_destroy_userprefix(userprefix);
+ return rc;
+}
+
+void cil_destroy_userprefix(struct cil_userprefix *userprefix)
+{
+ if (userprefix == NULL) {
+ return;
+ }
+
+ free(userprefix);
+}
+
+int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_selinuxuser *selinuxuser = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_selinuxuser_init(&selinuxuser);
+
+ selinuxuser->name_str = parse_current->next->data;
+ selinuxuser->user_str = parse_current->next->next->data;
+
+ if (parse_current->next->next->next->cl_head == NULL) {
+ selinuxuser->range_str = parse_current->next->next->next->data;
+ } else {
+ cil_levelrange_init(&selinuxuser->range);
+
+ rc = cil_fill_levelrange(parse_current->next->next->next->cl_head, selinuxuser->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = selinuxuser;
+ ast_node->flavor = CIL_SELINUXUSER;
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuser declaration");
+ cil_destroy_selinuxuser(selinuxuser);
+ return rc;
+}
+
+int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_selinuxuser *selinuxuser = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_selinuxuser_init(&selinuxuser);
+
+ selinuxuser->name_str = cil_strpool_add("__default__");
+ selinuxuser->user_str = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ selinuxuser->range_str = parse_current->next->next->data;
+ } else {
+ cil_levelrange_init(&selinuxuser->range);
+
+ rc = cil_fill_levelrange(parse_current->next->next->cl_head, selinuxuser->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = selinuxuser;
+ ast_node->flavor = CIL_SELINUXUSERDEFAULT;
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuserdefault declaration");
+ cil_destroy_selinuxuser(selinuxuser);
+ return rc;
+}
+
+void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser)
+{
+ if (selinuxuser == NULL) {
+ return;
+ }
+
+ if (selinuxuser->range_str == NULL && selinuxuser->range != NULL) {
+ cil_destroy_levelrange(selinuxuser->range);
+ }
+
+ free(selinuxuser);
+}
+
+int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_role *role = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_role_init(&role);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)role, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad role declaration");
+ cil_destroy_role(role);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_role(struct cil_role *role)
+{
+ if (role == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&role->datum);
+ ebitmap_destroy(role->types);
+ free(role->types);
+ free(role);
+}
+
+int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_roletype *roletype = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_roletype_init(&roletype);
+
+ roletype->role_str = parse_current->next->data;
+ roletype->type_str = parse_current->next->next->data;
+
+ ast_node->data = roletype;
+ ast_node->flavor = CIL_ROLETYPE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad roletype declaration");
+ cil_destroy_roletype(roletype);
+ return rc;
+}
+
+void cil_destroy_roletype(struct cil_roletype *roletype)
+{
+ if (roletype == NULL) {
+ return;
+ }
+
+ free(roletype);
+}
+
+int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_userrole *userrole = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_userrole_init(&userrole);
+
+ userrole->user_str = parse_current->next->data;
+ userrole->role_str = parse_current->next->next->data;
+
+ ast_node->data = userrole;
+ ast_node->flavor = CIL_USERROLE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad userrole declaration");
+ cil_destroy_userrole(userrole);
+ return rc;
+}
+
+void cil_destroy_userrole(struct cil_userrole *userrole)
+{
+ if (userrole == NULL) {
+ return;
+ }
+
+ free(userrole);
+}
+
+int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_roletransition *roletrans = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_roletransition_init(&roletrans);
+
+ roletrans->src_str = parse_current->next->data;
+ roletrans->tgt_str = parse_current->next->next->data;
+ roletrans->obj_str = parse_current->next->next->next->data;
+ roletrans->result_str = parse_current->next->next->next->next->data;
+
+ ast_node->data = roletrans;
+ ast_node->flavor = CIL_ROLETRANSITION;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad roletransition rule");
+ cil_destroy_roletransition(roletrans);
+ return rc;
+}
+
+void cil_destroy_roletransition(struct cil_roletransition *roletrans)
+{
+ if (roletrans == NULL) {
+ return;
+ }
+
+ free(roletrans);
+}
+
+int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_roleallow *roleallow = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_roleallow_init(&roleallow);
+
+ roleallow->src_str = parse_current->next->data;
+ roleallow->tgt_str = parse_current->next->next->data;
+
+ ast_node->data = roleallow;
+ ast_node->flavor = CIL_ROLEALLOW;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad roleallow rule");
+ cil_destroy_roleallow(roleallow);
+ return rc;
+}
+
+void cil_destroy_roleallow(struct cil_roleallow *roleallow)
+{
+ if (roleallow == NULL) {
+ return;
+ }
+
+ free(roleallow);
+}
+
+int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_roleattribute *attr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->data == CIL_KEY_SELF) {
+ cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_roleattribute_init(&attr);
+
+ key = parse_current->next->data;
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLEATTRIBUTE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad roleattribute declaration");
+ cil_destroy_roleattribute(attr);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_roleattribute(struct cil_roleattribute *attr)
+{
+ if (attr == NULL) {
+ return;
+ }
+
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ struct cil_list_item *expr = attr->expr_list->head;
+ while (expr != NULL) {
+ struct cil_list_item *next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+
+ cil_symtab_datum_destroy(&attr->datum);
+ ebitmap_destroy(attr->roles);
+ free(attr->roles);
+ free(attr);
+}
+
+int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_roleattributeset *attrset = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_roleattributeset_init(&attrset);
+
+ attrset->attr_str = parse_current->next->data;
+
+ rc = cil_gen_expr(parse_current->next->next, CIL_ROLE, &attrset->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ ast_node->data = attrset;
+ ast_node->flavor = CIL_ROLEATTRIBUTESET;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad roleattributeset declaration");
+ cil_destroy_roleattributeset(attrset);
+
+ return rc;
+}
+
+void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset)
+{
+ if (attrset == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+ cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+ free(attrset);
+}
+
+int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_avrule *rule = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_avrule_init(&rule);
+
+ rule->is_extended = 0;
+ rule->rule_kind = rule_kind;
+
+ rule->src_str = parse_current->next->data;
+ rule->tgt_str = parse_current->next->next->data;
+
+ rc = cil_fill_classperms_list(parse_current->next->next->next, &rule->perms.classperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = rule;
+ ast_node->flavor = CIL_AVRULE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad allow rule");
+ cil_destroy_avrule(rule);
+ return rc;
+}
+
+void cil_destroy_avrule(struct cil_avrule *rule)
+{
+ if (rule == NULL) {
+ return;
+ }
+
+ if (!rule->is_extended) {
+ cil_destroy_classperms_list(&rule->perms.classperms);
+ } else {
+ if (rule->perms.x.permx_str == NULL && rule->perms.x.permx != NULL) {
+ cil_destroy_permissionx(rule->perms.x.permx);
+ }
+ }
+
+ free(rule);
+}
+
+int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->data == CIL_KEY_IOCTL) {
+ permx->kind = CIL_PERMX_KIND_IOCTL;
+ } else {
+ cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ permx->obj_str = parse_current->next->data;
+
+ rc = cil_gen_expr(parse_current->next->next, CIL_PERMISSIONX, &permx->expr_str);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad permissionx content");
+ return rc;
+}
+
+int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_permissionx *permx = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_permissionx_init(&permx);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)permx, (hashtab_key_t)key, CIL_SYM_PERMX, CIL_PERMISSIONX);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fill_permissionx(parse_current->next->next->cl_head, permx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad permissionx statement");
+ cil_destroy_permissionx(permx);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_permissionx(struct cil_permissionx *permx)
+{
+ if (permx == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&permx->datum);
+
+ cil_list_destroy(&permx->expr_str, CIL_TRUE);
+ ebitmap_destroy(permx->perms);
+ free(permx->perms);
+ free(permx);
+}
+
+int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_avrule *rule = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_avrule_init(&rule);
+
+ rule->is_extended = 1;
+ rule->rule_kind = rule_kind;
+ rule->src_str = parse_current->next->data;
+ rule->tgt_str = parse_current->next->next->data;
+
+ if (parse_current->next->next->next->cl_head == NULL) {
+ rule->perms.x.permx_str = parse_current->next->next->next->data;
+ } else {
+ cil_permissionx_init(&rule->perms.x.permx);
+
+ rc = cil_fill_permissionx(parse_current->next->next->next->cl_head, rule->perms.x.permx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = rule;
+ ast_node->flavor = CIL_AVRULEX;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad allowx rule");
+ cil_destroy_avrule(rule);
+ return rc;
+}
+
+int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_type_rule *rule = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_type_rule_init(&rule);
+
+ rule->rule_kind = rule_kind;
+ rule->src_str = parse_current->next->data;
+ rule->tgt_str = parse_current->next->next->data;
+ rule->obj_str = parse_current->next->next->next->data;
+ rule->result_str = parse_current->next->next->next->next->data;
+
+ ast_node->data = rule;
+ ast_node->flavor = CIL_TYPE_RULE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad type rule");
+ cil_destroy_type_rule(rule);
+ return rc;
+}
+
+void cil_destroy_type_rule(struct cil_type_rule *rule)
+{
+ if (rule == NULL) {
+ return;
+ }
+
+ free(rule);
+}
+
+int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_type *type = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->data == CIL_KEY_SELF) {
+ cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_type_init(&type);
+
+ key = parse_current->next->data;
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)type, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad type declaration");
+ cil_destroy_type(type);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_type(struct cil_type *type)
+{
+ if (type == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&type->datum);
+ free(type);
+}
+
+int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_typeattribute *attr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->data == CIL_KEY_SELF) {
+ cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_typeattribute_init(&attr);
+
+ key = parse_current->next->data;
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad typeattribute declaration");
+ cil_destroy_typeattribute(attr);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_typeattribute(struct cil_typeattribute *attr)
+{
+ if (attr == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&attr->datum);
+
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ struct cil_list_item *expr = attr->expr_list->head;
+ while (expr != NULL) {
+ struct cil_list_item *next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+ ebitmap_destroy(attr->types);
+ free(attr->types);
+ free(attr);
+}
+
+int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_bool *boolean = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_bool_init(&boolean);
+
+ key = parse_current->next->data;
+
+ if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
+ boolean->value = CIL_TRUE;
+ } else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
+ boolean->value = CIL_FALSE;
+ } else {
+ cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)boolean, (hashtab_key_t)key, CIL_SYM_BOOLS, CIL_BOOL);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ if (tunableif) {
+ cil_tree_log(parse_current, CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration");
+ } else {
+ cil_tree_log(parse_current, CIL_ERR, "Bad boolean declaration");
+ }
+ cil_destroy_bool(boolean);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_bool(struct cil_bool *boolean)
+{
+ if (boolean == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&boolean->datum);
+ free(boolean);
+}
+
+int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_tunable *tunable = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_tunable_init(&tunable);
+
+ key = parse_current->next->data;
+
+ if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
+ tunable->value = CIL_TRUE;
+ } else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
+ tunable->value = CIL_FALSE;
+ } else {
+ cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)tunable, (hashtab_key_t)key, CIL_SYM_TUNABLES, CIL_TUNABLE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad tunable declaration");
+ cil_destroy_tunable(tunable);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_tunable(struct cil_tunable *tunable)
+{
+ if (tunable == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&tunable->datum);
+ free(tunable);
+}
+
+static enum cil_flavor __cil_get_expr_operator_flavor(const char *op)
+{
+ if (op == NULL) return CIL_NONE;
+ else if (op == CIL_KEY_AND) return CIL_AND;
+ else if (op == CIL_KEY_OR) return CIL_OR;
+ else if (op == CIL_KEY_NOT) return CIL_NOT;
+ else if (op == CIL_KEY_EQ) return CIL_EQ; /* Only conditional */
+ else if (op == CIL_KEY_NEQ) return CIL_NEQ; /* Only conditional */
+ else if (op == CIL_KEY_XOR) return CIL_XOR;
+ else if (op == CIL_KEY_ALL) return CIL_ALL; /* Only set and permissionx */
+ else if (op == CIL_KEY_RANGE) return CIL_RANGE; /* Only catset and permissionx */
+ else return CIL_NONE;
+}
+
+static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth);
+
+static int __cil_fill_expr_helper(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
+{
+ int rc = SEPOL_ERR;
+ enum cil_flavor op;
+
+ if (flavor == CIL_BOOL && *depth > COND_EXPR_MAXDEPTH) {
+ cil_log(CIL_ERR, "Max depth of %d exceeded for boolean expression\n", COND_EXPR_MAXDEPTH);
+ goto exit;
+ }
+
+ op = __cil_get_expr_operator_flavor(current->data);
+
+ rc = cil_verify_expr_syntax(current, op, flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (op != CIL_NONE) {
+ cil_list_append(expr, CIL_OP, (void *)op);
+ current = current->next;
+ }
+
+ if (op == CIL_NONE || op == CIL_ALL) {
+ (*depth)++;
+ }
+
+ for (;current != NULL; current = current->next) {
+ rc = __cil_fill_expr(current, flavor, expr, depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ (*depth)--;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
+{
+ int rc = SEPOL_ERR;
+
+ if (current->cl_head == NULL) {
+ enum cil_flavor op = __cil_get_expr_operator_flavor(current->data);
+ if (op != CIL_NONE) {
+ cil_log(CIL_ERR, "Operator (%s) not in an expression\n", (char*)current->data);
+ goto exit;
+ }
+ cil_list_append(expr, CIL_STRING, current->data);
+ } else {
+ struct cil_list *sub_expr;
+ cil_list_init(&sub_expr, flavor);
+ rc = __cil_fill_expr_helper(current->cl_head, flavor, sub_expr, depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_append(expr, CIL_LIST, sub_expr);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
+{
+ int rc = SEPOL_ERR;
+ int depth = 0;
+
+ cil_list_init(expr, flavor);
+
+ if (current->cl_head == NULL) {
+ rc = __cil_fill_expr(current, flavor, *expr, &depth);
+ } else {
+ rc = __cil_fill_expr_helper(current->cl_head, flavor, *expr, &depth);
+ }
+
+ if (rc != SEPOL_OK) {
+ cil_list_destroy(expr, CIL_TRUE);
+ cil_log(CIL_ERR, "Bad expression\n");
+ }
+
+ return rc;
+}
+
+static enum cil_flavor __cil_get_constraint_operator_flavor(const char *op)
+{
+ if (op == CIL_KEY_AND) return CIL_AND;
+ else if (op == CIL_KEY_OR) return CIL_OR;
+ else if (op == CIL_KEY_NOT) return CIL_NOT;
+ else if (op == CIL_KEY_EQ) return CIL_EQ;
+ else if (op == CIL_KEY_NEQ) return CIL_NEQ;
+ else if (op == CIL_KEY_CONS_DOM) return CIL_CONS_DOM;
+ else if (op == CIL_KEY_CONS_DOMBY) return CIL_CONS_DOMBY;
+ else if (op == CIL_KEY_CONS_INCOMP) return CIL_CONS_INCOMP;
+ else return CIL_NONE;
+}
+
+static enum cil_flavor __cil_get_constraint_operand_flavor(const char *operand)
+{
+ if (operand == NULL) return CIL_LIST;
+ else if (operand == CIL_KEY_CONS_T1) return CIL_CONS_T1;
+ else if (operand == CIL_KEY_CONS_T2) return CIL_CONS_T2;
+ else if (operand == CIL_KEY_CONS_T3) return CIL_CONS_T3;
+ else if (operand == CIL_KEY_CONS_R1) return CIL_CONS_R1;
+ else if (operand == CIL_KEY_CONS_R2) return CIL_CONS_R2;
+ else if (operand == CIL_KEY_CONS_R3) return CIL_CONS_R3;
+ else if (operand == CIL_KEY_CONS_U1) return CIL_CONS_U1;
+ else if (operand == CIL_KEY_CONS_U2) return CIL_CONS_U2;
+ else if (operand == CIL_KEY_CONS_U3) return CIL_CONS_U3;
+ else if (operand == CIL_KEY_CONS_L1) return CIL_CONS_L1;
+ else if (operand == CIL_KEY_CONS_L2) return CIL_CONS_L2;
+ else if (operand == CIL_KEY_CONS_H1) return CIL_CONS_H1;
+ else if (operand == CIL_KEY_CONS_H2) return CIL_CONS_H2;
+ else return CIL_STRING;
+}
+
+static int __cil_fill_constraint_leaf_expr(struct cil_tree_node *current, enum cil_flavor expr_flavor, enum cil_flavor op, struct cil_list **leaf_expr)
+{
+ int rc = SEPOL_ERR;
+ enum cil_flavor leaf_expr_flavor = CIL_NONE;
+ enum cil_flavor l_flavor = CIL_NONE;
+ enum cil_flavor r_flavor = CIL_NONE;
+
+ l_flavor = __cil_get_constraint_operand_flavor(current->next->data);
+ r_flavor = __cil_get_constraint_operand_flavor(current->next->next->data);
+
+ switch (l_flavor) {
+ case CIL_CONS_U1:
+ case CIL_CONS_U2:
+ case CIL_CONS_U3:
+ leaf_expr_flavor = CIL_USER;
+ break;
+ case CIL_CONS_R1:
+ case CIL_CONS_R2:
+ case CIL_CONS_R3:
+ leaf_expr_flavor = CIL_ROLE;
+ break;
+ case CIL_CONS_T1:
+ case CIL_CONS_T2:
+ case CIL_CONS_T3:
+ leaf_expr_flavor = CIL_TYPE;
+ break;
+ case CIL_CONS_L1:
+ case CIL_CONS_L2:
+ case CIL_CONS_H1:
+ case CIL_CONS_H2:
+ leaf_expr_flavor = CIL_LEVEL;
+ break;
+ default:
+ cil_log(CIL_ERR, "Invalid left operand (%s)\n", (char*)current->next->data);
+ goto exit;
+ }
+
+ rc = cil_verify_constraint_leaf_expr_syntax(l_flavor, r_flavor, op, expr_flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_init(leaf_expr, leaf_expr_flavor);
+
+ cil_list_append(*leaf_expr, CIL_OP, (void *)op);
+
+ cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)l_flavor);
+
+ if (r_flavor == CIL_STRING) {
+ cil_list_append(*leaf_expr, CIL_STRING, current->next->next->data);
+ } else if (r_flavor == CIL_LIST) {
+ struct cil_list *sub_list;
+ cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list);
+ cil_list_append(*leaf_expr, CIL_LIST, &sub_list);
+ } else {
+ cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)r_flavor);
+ }
+
+ return SEPOL_OK;
+
+exit:
+
+ return SEPOL_ERR;
+}
+
+static int __cil_fill_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr, int *depth)
+{
+ int rc = SEPOL_ERR;
+ enum cil_flavor op;
+ struct cil_list *lexpr;
+ struct cil_list *rexpr;
+
+ if (current->data == NULL || current->cl_head != NULL) {
+ cil_log(CIL_ERR, "Expected a string at the start of the constraint expression\n");
+ goto exit;
+ }
+
+ if (*depth > CEXPR_MAXDEPTH) {
+ cil_log(CIL_ERR, "Max depth of %d exceeded for constraint expression\n", CEXPR_MAXDEPTH);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ op = __cil_get_constraint_operator_flavor(current->data);
+
+ rc = cil_verify_constraint_expr_syntax(current, op);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ switch (op) {
+ case CIL_EQ:
+ case CIL_NEQ:
+ case CIL_CONS_DOM:
+ case CIL_CONS_DOMBY:
+ case CIL_CONS_INCOMP:
+ (*depth)++;
+ rc = __cil_fill_constraint_leaf_expr(current, flavor, op, expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ case CIL_NOT:
+ rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_init(expr, flavor);
+ cil_list_append(*expr, CIL_OP, (void *)op);
+ cil_list_append(*expr, CIL_LIST, lexpr);
+ break;
+ default:
+ rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rc = __cil_fill_constraint_expr(current->next->next->cl_head, flavor, &rexpr, depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_init(expr, flavor);
+ cil_list_append(*expr, CIL_OP, (void *)op);
+ cil_list_append(*expr, CIL_LIST, lexpr);
+ cil_list_append(*expr, CIL_LIST, rexpr);
+ break;
+ }
+
+ (*depth)--;
+
+ return SEPOL_OK;
+exit:
+
+ return rc;
+}
+
+int cil_gen_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
+{
+ int rc = SEPOL_ERR;
+ int depth = 0;
+
+ if (current->cl_head == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_fill_constraint_expr(current->cl_head, flavor, expr, &depth);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+
+ cil_log(CIL_ERR, "Bad expression tree for constraint\n");
+ return rc;
+}
+
+int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_LIST,
+ CIL_SYN_LIST | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_booleanif *bif = NULL;
+ struct cil_tree_node *next = NULL;
+ struct cil_tree_node *cond = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_boolif_init(&bif);
+ bif->preserved_tunable = tunableif;
+
+ rc = cil_gen_expr(parse_current->next, CIL_BOOL, &bif->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cond = parse_current->next->next;
+
+ /* Destroying expr tree after stack is created*/
+ if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+ cond->cl_head->data != CIL_KEY_CONDFALSE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Conditional neither true nor false\n");
+ goto exit;
+ }
+
+ if (cond->next != NULL) {
+ cond = cond->next;
+ if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+ cond->cl_head->data != CIL_KEY_CONDFALSE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Conditional neither true nor false\n");
+ goto exit;
+ }
+ }
+
+
+ next = parse_current->next->next;
+ cil_tree_subtree_destroy(parse_current->next);
+ parse_current->next = next;
+
+ ast_node->flavor = CIL_BOOLEANIF;
+ ast_node->data = bif;
+
+ return SEPOL_OK;
+
+exit:
+ if (tunableif) {
+ cil_tree_log(parse_current, CIL_ERR, "Bad tunableif (treated as a booleanif due to preserve-tunables) declaration");
+ } else {
+ cil_tree_log(parse_current, CIL_ERR, "Bad booleanif declaration");
+ }
+ cil_destroy_boolif(bif);
+ return rc;
+}
+
+void cil_destroy_boolif(struct cil_booleanif *bif)
+{
+ if (bif == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&bif->str_expr, CIL_TRUE);
+ cil_list_destroy(&bif->datum_expr, CIL_FALSE);
+
+ free(bif);
+}
+
+int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_LIST,
+ CIL_SYN_LIST | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_tunableif *tif = NULL;
+ struct cil_tree_node *next = NULL;
+ struct cil_tree_node *cond = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_tunif_init(&tif);
+
+ rc = cil_gen_expr(parse_current->next, CIL_TUNABLE, &tif->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cond = parse_current->next->next;
+
+ if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+ cond->cl_head->data != CIL_KEY_CONDFALSE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Conditional neither true nor false\n");
+ goto exit;
+ }
+
+ if (cond->next != NULL) {
+ cond = cond->next;
+
+ if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
+ cond->cl_head->data != CIL_KEY_CONDFALSE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Conditional neither true nor false\n");
+ goto exit;
+ }
+ }
+
+ /* Destroying expr tree after stack is created*/
+ next = parse_current->next->next;
+ cil_tree_subtree_destroy(parse_current->next);
+ parse_current->next = next;
+
+ ast_node->flavor = CIL_TUNABLEIF;
+ ast_node->data = tif;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad tunableif declaration");
+ cil_destroy_tunif(tif);
+ return rc;
+}
+
+void cil_destroy_tunif(struct cil_tunableif *tif)
+{
+ if (tif == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&tif->str_expr, CIL_TRUE);
+ cil_list_destroy(&tif->datum_expr, CIL_FALSE);
+
+ free(tif);
+}
+
+int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_N_LISTS,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_condblock *cb = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (ast_node->parent->flavor != CIL_BOOLEANIF && ast_node->parent->flavor != CIL_TUNABLEIF) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Conditional statements must be a direct child of a tunableif or booleanif statement.\n");
+ goto exit;
+ }
+
+ ast_node->flavor = CIL_CONDBLOCK;
+
+ cil_condblock_init(&cb);
+ cb->flavor = flavor;
+
+ ast_node->data = cb;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad %s condition declaration",
+ (char*)parse_current->data);
+ cil_destroy_condblock(cb);
+ return rc;
+}
+
+void cil_destroy_condblock(struct cil_condblock *cb)
+{
+ if (cb == NULL) {
+ return;
+ }
+
+ cil_symtab_array_destroy(cb->symtab);
+ free(cb);
+}
+
+int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_alias *alias = NULL;
+ enum cil_sym_index sym_index;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) {
+ cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_alias_init(&alias);
+
+ key = parse_current->next->data;
+
+ rc = cil_flavor_to_symtab_index(flavor, &sym_index);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)alias, (hashtab_key_t)key, sym_index, flavor);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", (char*)parse_current->data);
+ cil_destroy_alias(alias);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_alias(struct cil_alias *alias)
+{
+ if (alias == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&alias->datum);
+ alias->actual = NULL;
+
+ free(alias);
+}
+
+int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_aliasactual *aliasactual = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if ((flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) || parse_current->next->next->data == CIL_KEY_SELF) {
+ cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_aliasactual_init(&aliasactual);
+
+ aliasactual->alias_str = parse_current->next->data;
+
+ aliasactual->actual_str = parse_current->next->next->data;
+
+ ast_node->data = aliasactual;
+ ast_node->flavor = flavor;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad %s association", cil_node_to_string(parse_current));
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual)
+{
+ if (aliasactual == NULL) {
+ return;
+ }
+
+ free(aliasactual);
+}
+
+int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_typeattributeset *attrset = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_typeattributeset_init(&attrset);
+
+ attrset->attr_str = parse_current->next->data;
+
+ rc = cil_gen_expr(parse_current->next->next, CIL_TYPE, &attrset->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ ast_node->data = attrset;
+ ast_node->flavor = CIL_TYPEATTRIBUTESET;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad typeattributeset statement");
+ cil_destroy_typeattributeset(attrset);
+ return rc;
+}
+
+void cil_destroy_typeattributeset(struct cil_typeattributeset *attrset)
+{
+ if (attrset == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&attrset->str_expr, CIL_TRUE);
+ cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
+
+ free(attrset);
+}
+
+int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_typepermissive *typeperm = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_typepermissive_init(&typeperm);
+
+ typeperm->type_str = parse_current->next->data;
+
+ ast_node->data = typeperm;
+ ast_node->flavor = CIL_TYPEPERMISSIVE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad typepermissive declaration");
+ cil_destroy_typepermissive(typeperm);
+ return rc;
+}
+
+void cil_destroy_typepermissive(struct cil_typepermissive *typeperm)
+{
+ if (typeperm == NULL) {
+ return;
+ }
+
+ free(typeperm);
+}
+
+int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *s1, *s2, *s3, *s4, *s5;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL ) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ s1 = parse_current->next->data;
+ s2 = parse_current->next->next->data;
+ s3 = parse_current->next->next->next->data;
+ s4 = parse_current->next->next->next->next->data;
+ s5 = NULL;
+
+ if (parse_current->next->next->next->next->next) {
+ if (s4 == CIL_KEY_STAR) {
+ s4 = parse_current->next->next->next->next->next->data;
+ } else {
+ s5 = parse_current->next->next->next->next->next->data;
+ }
+ }
+
+ if (s5) {
+ struct cil_nametypetransition *nametypetrans = NULL;
+
+ cil_nametypetransition_init(&nametypetrans);
+
+ nametypetrans->src_str = s1;
+ nametypetrans->tgt_str = s2;
+ nametypetrans->obj_str = s3;
+ nametypetrans->result_str = s5;
+ nametypetrans->name_str = s4;
+
+ ast_node->data = nametypetrans;
+ ast_node->flavor = CIL_NAMETYPETRANSITION;
+ } else {
+ struct cil_type_rule *rule = NULL;
+
+ cil_type_rule_init(&rule);
+
+ rule->rule_kind = CIL_TYPE_TRANSITION;
+ rule->src_str = s1;
+ rule->tgt_str = s2;
+ rule->obj_str = s3;
+ rule->result_str = s4;
+
+ ast_node->data = rule;
+ ast_node->flavor = CIL_TYPE_RULE;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad typetransition declaration");
+ return rc;
+}
+
+void cil_destroy_name(struct cil_name *name)
+{
+ if (name == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&name->datum);
+ free(name);
+}
+
+void cil_destroy_typetransition(struct cil_nametypetransition *nametypetrans)
+{
+ if (nametypetrans == NULL) {
+ return;
+ }
+
+ free(nametypetrans);
+}
+
+int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_rangetransition *rangetrans = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL ) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_rangetransition_init(&rangetrans);
+
+ rangetrans->src_str = parse_current->next->data;
+ rangetrans->exec_str = parse_current->next->next->data;
+ rangetrans->obj_str = parse_current->next->next->next->data;
+
+ rangetrans->range_str = NULL;
+
+ if (parse_current->next->next->next->next->cl_head == NULL) {
+ rangetrans->range_str = parse_current->next->next->next->next->data;
+ } else {
+ cil_levelrange_init(&rangetrans->range);
+
+ rc = cil_fill_levelrange(parse_current->next->next->next->next->cl_head, rangetrans->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = rangetrans;
+ ast_node->flavor = CIL_RANGETRANSITION;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad rangetransition declaration");
+ cil_destroy_rangetransition(rangetrans);
+ return rc;
+}
+
+void cil_destroy_rangetransition(struct cil_rangetransition *rangetrans)
+{
+ if (rangetrans == NULL) {
+ return;
+ }
+
+ if (rangetrans->range_str == NULL && rangetrans->range != NULL) {
+ cil_destroy_levelrange(rangetrans->range);
+ }
+
+ free(rangetrans);
+}
+
+int cil_gen_sensitivity(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_sens *sens = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_sens_init(&sens);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sens, (hashtab_key_t)key, CIL_SYM_SENS, CIL_SENS);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivity declaration");
+ cil_destroy_sensitivity(sens);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_sensitivity(struct cil_sens *sens)
+{
+ if (sens == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&sens->datum);
+
+ cil_list_destroy(&sens->cats_list, CIL_FALSE);
+
+ free(sens);
+}
+
+int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_cat *cat = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_cat_init(&cat);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)cat, (hashtab_key_t)key, CIL_SYM_CATS, CIL_CAT);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad category declaration");
+ cil_destroy_category(cat);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_category(struct cil_cat *cat)
+{
+ if (cat == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&cat->datum);
+ free(cat);
+}
+
+int cil_gen_catset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_catset *catset = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_catset_init(&catset);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)catset, (hashtab_key_t)key, CIL_SYM_CATS, CIL_CATSET);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fill_cats(parse_current->next->next, &catset->cats);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad categoryset declaration");
+ cil_destroy_catset(catset);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_catset(struct cil_catset *catset)
+{
+ if (catset == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&catset->datum);
+
+ cil_destroy_cats(catset->cats);
+
+ free(catset);
+}
+
+int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_catorder *catorder = NULL;
+ struct cil_list_item *curr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_catorder_init(&catorder);
+
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_CATORDER, &catorder->cat_list_str);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_for_each(curr, catorder->cat_list_str) {
+ if (curr->data == CIL_KEY_UNORDERED) {
+ cil_log(CIL_ERR, "Category order cannot be unordered.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ ast_node->data = catorder;
+ ast_node->flavor = CIL_CATORDER;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad categoryorder declaration");
+ cil_destroy_catorder(catorder);
+ return rc;
+}
+
+void cil_destroy_catorder(struct cil_catorder *catorder)
+{
+ if (catorder == NULL) {
+ return;
+ }
+
+ if (catorder->cat_list_str != NULL) {
+ cil_list_destroy(&catorder->cat_list_str, 1);
+ }
+
+ free(catorder);
+}
+
+int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_sensorder *sensorder = NULL;
+ struct cil_list_item *curr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_sensorder_init(&sensorder);
+
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_SENSITIVITYORDER, &sensorder->sens_list_str);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_list_for_each(curr, sensorder->sens_list_str) {
+ if (curr->data == CIL_KEY_UNORDERED) {
+ cil_log(CIL_ERR, "Sensitivy order cannot be unordered.\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ ast_node->data = sensorder;
+ ast_node->flavor = CIL_SENSITIVITYORDER;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivityorder declaration");
+ cil_destroy_sensitivityorder(sensorder);
+ return rc;
+}
+
+void cil_destroy_sensitivityorder(struct cil_sensorder *sensorder)
+{
+ if (sensorder == NULL) {
+ return;
+ }
+
+ if (sensorder->sens_list_str != NULL) {
+ cil_list_destroy(&sensorder->sens_list_str, CIL_TRUE);
+ }
+
+ free(sensorder);
+}
+
+int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_senscat *senscat = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_senscat_init(&senscat);
+
+ senscat->sens_str = parse_current->next->data;
+
+ rc = cil_fill_cats(parse_current->next->next, &senscat->cats);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = senscat;
+ ast_node->flavor = CIL_SENSCAT;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivitycategory declaration");
+ cil_destroy_senscat(senscat);
+ return rc;
+}
+
+void cil_destroy_senscat(struct cil_senscat *senscat)
+{
+ if (senscat == NULL) {
+ return;
+ }
+
+ cil_destroy_cats(senscat->cats);
+
+ free(senscat);
+}
+
+int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_level *level = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_level_init(&level);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)level, (hashtab_key_t)key, CIL_SYM_LEVELS, CIL_LEVEL);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fill_level(parse_current->next->next->cl_head, level);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad level declaration");
+ cil_destroy_level(level);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_level(struct cil_level *level)
+{
+ if (level == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&level->datum);
+
+ cil_destroy_cats(level->cats);
+
+ free(level);
+}
+
+/* low should be pointing to either the name of the low level or to an open paren for an anonymous low level */
+int cil_fill_levelrange(struct cil_tree_node *low, struct cil_levelrange *lvlrange)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+
+ if (low == NULL || lvlrange == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(low, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+
+ goto exit;
+ }
+
+ if (low->cl_head == NULL) {
+ lvlrange->low_str = low->data;
+ } else {
+ cil_level_init(&lvlrange->low);
+ rc = cil_fill_level(low->cl_head, lvlrange->low);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (low->next->cl_head == NULL) {
+ lvlrange->high_str = low->next->data;
+ } else {
+ cil_level_init(&lvlrange->high);
+ rc = cil_fill_level(low->next->cl_head, lvlrange->high);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad levelrange\n");
+ return rc;
+}
+
+int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_levelrange *lvlrange = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_levelrange_init(&lvlrange);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)lvlrange, (hashtab_key_t)key, CIL_SYM_LEVELRANGES, CIL_LEVELRANGE);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fill_levelrange(parse_current->next->next->cl_head, lvlrange);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad levelrange declaration");
+ cil_destroy_levelrange(lvlrange);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_levelrange(struct cil_levelrange *lvlrange)
+{
+ if (lvlrange == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&lvlrange->datum);
+
+ if (lvlrange->low_str == NULL) {
+ cil_destroy_level(lvlrange->low);
+ }
+
+ if (lvlrange->high_str == NULL) {
+ cil_destroy_level(lvlrange->high);
+ }
+
+ free(lvlrange);
+}
+
+int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_constrain *cons = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_constrain_init(&cons);
+
+ rc = cil_fill_classperms_list(parse_current->next, &cons->classperms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_constraint_expr(parse_current->next->next, flavor, &cons->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = cons;
+ ast_node->flavor = flavor;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad constrain declaration");
+ cil_destroy_constrain(cons);
+ return rc;
+}
+
+void cil_destroy_constrain(struct cil_constrain *cons)
+{
+ if (cons == NULL) {
+ return;
+ }
+
+ cil_destroy_classperms_list(&cons->classperms);
+ cil_list_destroy(&cons->str_expr, CIL_TRUE);
+ cil_list_destroy(&cons->datum_expr, CIL_FALSE);
+
+ free(cons);
+}
+
+int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_validatetrans *validtrans = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_validatetrans_init(&validtrans);
+
+ validtrans->class_str = parse_current->next->data;
+
+ rc = cil_gen_constraint_expr(parse_current->next->next, flavor, &validtrans->str_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ ast_node->data = validtrans;
+ ast_node->flavor = flavor;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad validatetrans declaration");
+ cil_destroy_validatetrans(validtrans);
+ return rc;
+
+
+}
+
+void cil_destroy_validatetrans(struct cil_validatetrans *validtrans)
+{
+ if (validtrans == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&validtrans->str_expr, CIL_TRUE);
+ cil_list_destroy(&validtrans->datum_expr, CIL_FALSE);
+
+ free(validtrans);
+}
+
+/* Fills in context starting from user */
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+
+ if (user_node == NULL || context == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(user_node, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ context->user_str = user_node->data;
+ context->role_str = user_node->next->data;
+ context->type_str = user_node->next->next->data;
+
+ context->range_str = NULL;
+
+ if (user_node->next->next->next->cl_head == NULL) {
+ context->range_str = user_node->next->next->next->data;
+ } else {
+ cil_levelrange_init(&context->range);
+
+ rc = cil_fill_levelrange(user_node->next->next->next->cl_head, context->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad context\n");
+ return rc;
+}
+
+int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_context *context = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_context_init(&context);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)context, (hashtab_key_t)key, CIL_SYM_CONTEXTS, CIL_CONTEXT);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad context declaration");
+ cil_destroy_context(context);
+ cil_clear_node(ast_node);
+ return SEPOL_ERR;
+}
+
+void cil_destroy_context(struct cil_context *context)
+{
+ if (context == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&context->datum);;
+
+ if (context->range_str == NULL && context->range != NULL) {
+ cil_destroy_levelrange(context->range);
+ }
+
+ free(context);
+}
+
+int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_filecon *filecon = NULL;
+ char *type = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ type = parse_current->next->next->data;
+ cil_filecon_init(&filecon);
+
+ filecon->path_str = parse_current->next->data;
+
+ if (type == CIL_KEY_FILE) {
+ filecon->type = CIL_FILECON_FILE;
+ } else if (type == CIL_KEY_DIR) {
+ filecon->type = CIL_FILECON_DIR;
+ } else if (type == CIL_KEY_CHAR) {
+ filecon->type = CIL_FILECON_CHAR;
+ } else if (type == CIL_KEY_BLOCK) {
+ filecon->type = CIL_FILECON_BLOCK;
+ } else if (type == CIL_KEY_SOCKET) {
+ filecon->type = CIL_FILECON_SOCKET;
+ } else if (type == CIL_KEY_PIPE) {
+ filecon->type = CIL_FILECON_PIPE;
+ } else if (type == CIL_KEY_SYMLINK) {
+ filecon->type = CIL_FILECON_SYMLINK;
+ } else if (type == CIL_KEY_ANY) {
+ filecon->type = CIL_FILECON_ANY;
+ } else {
+ cil_log(CIL_ERR, "Invalid file type\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (parse_current->next->next->next->cl_head == NULL) {
+ filecon->context_str = parse_current->next->next->next->data;
+ } else {
+ if (parse_current->next->next->next->cl_head->next == NULL) {
+ filecon->context = NULL;
+ } else {
+ cil_context_init(&filecon->context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, filecon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ ast_node->data = filecon;
+ ast_node->flavor = CIL_FILECON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad filecon declaration");
+ cil_destroy_filecon(filecon);
+ return rc;
+}
+
+//TODO: Should we be checking if the pointer is NULL when passed in?
+void cil_destroy_filecon(struct cil_filecon *filecon)
+{
+ if (filecon == NULL) {
+ return;
+ }
+
+ if (filecon->context_str == NULL && filecon->context != NULL) {
+ cil_destroy_context(filecon->context);
+ }
+
+ free(filecon);
+}
+
+int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_portcon *portcon = NULL;
+ char *proto;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_portcon_init(&portcon);
+
+ proto = parse_current->next->data;
+ if (proto == CIL_KEY_UDP) {
+ portcon->proto = CIL_PROTOCOL_UDP;
+ } else if (proto == CIL_KEY_TCP) {
+ portcon->proto = CIL_PROTOCOL_TCP;
+ } else if (proto == CIL_KEY_DCCP) {
+ portcon->proto = CIL_PROTOCOL_DCCP;
+ } else {
+ cil_log(CIL_ERR, "Invalid protocol\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (parse_current->next->next->cl_head != NULL) {
+ if (parse_current->next->next->cl_head->next != NULL
+ && parse_current->next->next->cl_head->next->next == NULL) {
+ rc = cil_fill_integer(parse_current->next->next->cl_head, &portcon->port_low);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper port specified\n");
+ goto exit;
+ }
+ rc = cil_fill_integer(parse_current->next->next->cl_head->next, &portcon->port_high);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper port specified\n");
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR, "Improper port range specified\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ rc = cil_fill_integer(parse_current->next->next, &portcon->port_low);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper port specified\n");
+ goto exit;
+ }
+ portcon->port_high = portcon->port_low;
+ }
+
+ if (parse_current->next->next->next->cl_head == NULL ) {
+ portcon->context_str = parse_current->next->next->next->data;
+ } else {
+ cil_context_init(&portcon->context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, portcon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = portcon;
+ ast_node->flavor = CIL_PORTCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad portcon declaration");
+ cil_destroy_portcon(portcon);
+ return rc;
+}
+
+void cil_destroy_portcon(struct cil_portcon *portcon)
+{
+ if (portcon == NULL) {
+ return;
+ }
+
+ if (portcon->context_str == NULL && portcon->context != NULL) {
+ cil_destroy_context(portcon->context);
+ }
+
+ free(portcon);
+}
+
+int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_nodecon *nodecon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_nodecon_init(&nodecon);
+
+ if (parse_current->next->cl_head == NULL ) {
+ nodecon->addr_str = parse_current->next->data;
+ } else {
+ cil_ipaddr_init(&nodecon->addr);
+
+ rc = cil_fill_ipaddr(parse_current->next->cl_head, nodecon->addr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (parse_current->next->next->cl_head == NULL ) {
+ nodecon->mask_str = parse_current->next->next->data;
+ } else {
+ cil_ipaddr_init(&nodecon->mask);
+
+ rc = cil_fill_ipaddr(parse_current->next->next->cl_head, nodecon->mask);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (parse_current->next->next->next->cl_head == NULL ) {
+ nodecon->context_str = parse_current->next->next->next->data;
+ } else {
+ cil_context_init(&nodecon->context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, nodecon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = nodecon;
+ ast_node->flavor = CIL_NODECON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad nodecon declaration");
+ cil_destroy_nodecon(nodecon);
+ return rc;
+}
+
+void cil_destroy_nodecon(struct cil_nodecon *nodecon)
+{
+ if (nodecon == NULL) {
+ return;
+ }
+
+ if (nodecon->addr_str == NULL && nodecon->addr != NULL) {
+ cil_destroy_ipaddr(nodecon->addr);
+ }
+
+ if (nodecon->mask_str == NULL && nodecon->mask != NULL) {
+ cil_destroy_ipaddr(nodecon->mask);
+ }
+
+ if (nodecon->context_str == NULL && nodecon->context != NULL) {
+ cil_destroy_context(nodecon->context);
+ }
+
+ free(nodecon);
+}
+
+int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_genfscon *genfscon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_genfscon_init(&genfscon);
+
+ genfscon->fs_str = parse_current->next->data;
+ genfscon->path_str = parse_current->next->next->data;
+
+ if (parse_current->next->next->next->cl_head == NULL ) {
+ genfscon->context_str = parse_current->next->next->next->data;
+ } else {
+ cil_context_init(&genfscon->context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, genfscon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = genfscon;
+ ast_node->flavor = CIL_GENFSCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad genfscon declaration");
+ cil_destroy_genfscon(genfscon);
+ return SEPOL_ERR;
+}
+
+void cil_destroy_genfscon(struct cil_genfscon *genfscon)
+{
+ if (genfscon == NULL) {
+ return;
+ }
+
+ if (genfscon->context_str == NULL && genfscon->context != NULL) {
+ cil_destroy_context(genfscon->context);
+ }
+
+ free(genfscon);
+}
+
+
+int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_netifcon *netifcon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_netifcon_init(&netifcon);
+
+ netifcon->interface_str = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ netifcon->if_context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&netifcon->if_context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, netifcon->if_context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (parse_current->next->next->next->cl_head == NULL) {
+ netifcon->packet_context_str = parse_current->next->next->next->data;
+ } else {
+ cil_context_init(&netifcon->packet_context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, netifcon->packet_context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = netifcon;
+ ast_node->flavor = CIL_NETIFCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad netifcon declaration");
+ cil_destroy_netifcon(netifcon);
+ return SEPOL_ERR;
+}
+
+void cil_destroy_netifcon(struct cil_netifcon *netifcon)
+{
+ if (netifcon == NULL) {
+ return;
+ }
+
+ if (netifcon->if_context_str == NULL && netifcon->if_context != NULL) {
+ cil_destroy_context(netifcon->if_context);
+ }
+
+ if (netifcon->packet_context_str == NULL && netifcon->packet_context != NULL) {
+ cil_destroy_context(netifcon->packet_context);
+ }
+
+ free(netifcon);
+}
+
+int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_pirqcon *pirqcon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_pirqcon_init(&pirqcon);
+
+ rc = cil_fill_integer(parse_current->next, &pirqcon->pirq);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->next->cl_head == NULL) {
+ pirqcon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&pirqcon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, pirqcon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = pirqcon;
+ ast_node->flavor = CIL_PIRQCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad pirqcon declaration");
+ cil_destroy_pirqcon(pirqcon);
+ return rc;
+}
+
+void cil_destroy_pirqcon(struct cil_pirqcon *pirqcon)
+{
+ if (pirqcon == NULL) {
+ return;
+ }
+
+ if (pirqcon->context_str == NULL && pirqcon->context != NULL) {
+ cil_destroy_context(pirqcon->context);
+ }
+
+ free(pirqcon);
+}
+
+int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_iomemcon *iomemcon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_iomemcon_init(&iomemcon);
+
+ if (parse_current->next->cl_head != NULL) {
+ if (parse_current->next->cl_head->next != NULL &&
+ parse_current->next->cl_head->next->next == NULL) {
+ rc = cil_fill_integer64(parse_current->next->cl_head, &iomemcon->iomem_low);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper iomem specified\n");
+ goto exit;
+ }
+ rc = cil_fill_integer64(parse_current->next->cl_head->next, &iomemcon->iomem_high);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper iomem specified\n");
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR, "Improper iomem range specified\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ rc = cil_fill_integer64(parse_current->next, &iomemcon->iomem_low);;
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper iomem specified\n");
+ goto exit;
+ }
+ iomemcon->iomem_high = iomemcon->iomem_low;
+ }
+
+ if (parse_current->next->next->cl_head == NULL ) {
+ iomemcon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&iomemcon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, iomemcon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = iomemcon;
+ ast_node->flavor = CIL_IOMEMCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad iomemcon declaration");
+ cil_destroy_iomemcon(iomemcon);
+ return rc;
+}
+
+void cil_destroy_iomemcon(struct cil_iomemcon *iomemcon)
+{
+ if (iomemcon == NULL) {
+ return;
+ }
+
+ if (iomemcon->context_str == NULL && iomemcon->context != NULL) {
+ cil_destroy_context(iomemcon->context);
+ }
+
+ free(iomemcon);
+}
+
+int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_ioportcon *ioportcon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_ioportcon_init(&ioportcon);
+
+ if (parse_current->next->cl_head != NULL) {
+ if (parse_current->next->cl_head->next != NULL &&
+ parse_current->next->cl_head->next->next == NULL) {
+ rc = cil_fill_integer(parse_current->next->cl_head, &ioportcon->ioport_low);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper ioport specified\n");
+ goto exit;
+ }
+ rc = cil_fill_integer(parse_current->next->cl_head->next, &ioportcon->ioport_high);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper ioport specified\n");
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR, "Improper ioport range specified\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ rc = cil_fill_integer(parse_current->next, &ioportcon->ioport_low);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Improper ioport specified\n");
+ goto exit;
+ }
+ ioportcon->ioport_high = ioportcon->ioport_low;
+ }
+
+ if (parse_current->next->next->cl_head == NULL ) {
+ ioportcon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&ioportcon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, ioportcon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = ioportcon;
+ ast_node->flavor = CIL_IOPORTCON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad ioportcon declaration");
+ cil_destroy_ioportcon(ioportcon);
+ return rc;
+}
+
+void cil_destroy_ioportcon(struct cil_ioportcon *ioportcon)
+{
+ if (ioportcon == NULL) {
+ return;
+ }
+
+ if (ioportcon->context_str == NULL && ioportcon->context != NULL) {
+ cil_destroy_context(ioportcon->context);
+ }
+
+ free(ioportcon);
+}
+
+int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_pcidevicecon *pcidevicecon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_pcidevicecon_init(&pcidevicecon);
+
+ rc = cil_fill_integer(parse_current->next, &pcidevicecon->dev);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (parse_current->next->next->cl_head == NULL) {
+ pcidevicecon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&pcidevicecon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, pcidevicecon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = pcidevicecon;
+ ast_node->flavor = CIL_PCIDEVICECON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad pcidevicecon declaration");
+ cil_destroy_pcidevicecon(pcidevicecon);
+ return rc;
+}
+
+void cil_destroy_pcidevicecon(struct cil_pcidevicecon *pcidevicecon)
+{
+ if (pcidevicecon == NULL) {
+ return;
+ }
+
+ if (pcidevicecon->context_str == NULL && pcidevicecon->context != NULL) {
+ cil_destroy_context(pcidevicecon->context);
+ }
+
+ free(pcidevicecon);
+}
+
+int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ int rc = SEPOL_ERR;
+ struct cil_devicetreecon *devicetreecon = NULL;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_devicetreecon_init(&devicetreecon);
+
+ devicetreecon->path = parse_current->next->data;
+
+ if (parse_current->next->next->cl_head == NULL) {
+ devicetreecon->context_str = parse_current->next->next->data;
+ } else {
+ cil_context_init(&devicetreecon->context);
+
+ rc = cil_fill_context(parse_current->next->next->cl_head, devicetreecon->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = devicetreecon;
+ ast_node->flavor = CIL_DEVICETREECON;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad devicetreecon declaration");
+ cil_destroy_devicetreecon(devicetreecon);
+ return rc;
+}
+
+void cil_destroy_devicetreecon(struct cil_devicetreecon *devicetreecon)
+{
+ if (devicetreecon == NULL) {
+ return;
+ }
+
+ if (devicetreecon->context_str == NULL && devicetreecon->context != NULL) {
+ cil_destroy_context(devicetreecon->context);
+ }
+
+ free(devicetreecon);
+}
+
+int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *type = NULL;
+ struct cil_fsuse *fsuse = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ type = parse_current->next->data;
+
+ cil_fsuse_init(&fsuse);
+
+ if (type == CIL_KEY_XATTR) {
+ fsuse->type = CIL_FSUSE_XATTR;
+ } else if (type == CIL_KEY_TASK) {
+ fsuse->type = CIL_FSUSE_TASK;
+ } else if (type == CIL_KEY_TRANS) {
+ fsuse->type = CIL_FSUSE_TRANS;
+ } else {
+ cil_log(CIL_ERR, "Invalid fsuse type\n");
+ goto exit;
+ }
+
+ fsuse->fs_str = parse_current->next->next->data;
+
+ if (parse_current->next->next->next->cl_head == NULL) {
+ fsuse->context_str = parse_current->next->next->next->data;
+ } else {
+ cil_context_init(&fsuse->context);
+
+ rc = cil_fill_context(parse_current->next->next->next->cl_head, fsuse->context);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ ast_node->data = fsuse;
+ ast_node->flavor = CIL_FSUSE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad fsuse declaration");
+ cil_destroy_fsuse(fsuse);
+ return SEPOL_ERR;
+}
+
+void cil_destroy_fsuse(struct cil_fsuse *fsuse)
+{
+ if (fsuse == NULL) {
+ return;
+ }
+
+ if (fsuse->context_str == NULL && fsuse->context != NULL) {
+ cil_destroy_context(fsuse->context);
+ }
+
+ free(fsuse);
+}
+
+void cil_destroy_param(struct cil_param *param)
+{
+ if (param == NULL) {
+ return;
+ }
+
+ free(param);
+}
+
+int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ char *key = NULL;
+ struct cil_macro *macro = NULL;
+ struct cil_tree_node *macro_content = NULL;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
+ CIL_SYN_N_LISTS | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/ sizeof(*syntax);
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc =__cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_macro_init(¯o);
+
+ key = parse_current->next->data;
+
+ struct cil_tree_node *current_item = parse_current->next->next->cl_head;
+ while (current_item != NULL) {
+ enum cil_syntax param_syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax);
+ char *kind = NULL;
+ struct cil_param *param = NULL;
+
+ rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (macro->params == NULL) {
+ cil_list_init(¯o->params, CIL_LIST_ITEM);
+ }
+
+ kind = current_item->cl_head->data;
+ cil_param_init(¶m);
+
+ if (kind == CIL_KEY_TYPE) {
+ param->flavor = CIL_TYPE;
+ } else if (kind == CIL_KEY_ROLE) {
+ param->flavor = CIL_ROLE;
+ } else if (kind == CIL_KEY_USER) {
+ param->flavor = CIL_USER;
+ } else if (kind == CIL_KEY_SENSITIVITY) {
+ param->flavor = CIL_SENS;
+ } else if (kind == CIL_KEY_CATEGORY) {
+ param->flavor = CIL_CAT;
+ } else if (kind == CIL_KEY_CATSET) {
+ param->flavor = CIL_CATSET;
+ } else if (kind == CIL_KEY_LEVEL) {
+ param->flavor = CIL_LEVEL;
+ } else if (kind == CIL_KEY_LEVELRANGE) {
+ param->flavor = CIL_LEVELRANGE;
+ } else if (kind == CIL_KEY_CLASS) {
+ param->flavor = CIL_CLASS;
+ } else if (kind == CIL_KEY_IPADDR) {
+ param->flavor = CIL_IPADDR;
+ } else if (kind == CIL_KEY_MAP_CLASS) {
+ param->flavor = CIL_MAP_CLASS;
+ } else if (kind == CIL_KEY_CLASSPERMISSION) {
+ param->flavor = CIL_CLASSPERMISSION;
+ } else if (kind == CIL_KEY_BOOL) {
+ param->flavor = CIL_BOOL;
+ } else if (kind == CIL_KEY_STRING) {
+ param->flavor = CIL_NAME;
+ } else if (kind == CIL_KEY_NAME) {
+ param->flavor = CIL_NAME;
+ } else {
+ cil_log(CIL_ERR, "The kind %s is not allowed as a parameter\n",kind);
+ cil_destroy_param(param);
+ goto exit;
+ }
+
+ param->str = current_item->cl_head->next->data;
+
+ rc = __cil_verify_name(param->str);
+ if (rc != SEPOL_OK) {
+ cil_destroy_param(param);
+ goto exit;
+ }
+
+ //walk current list and check for duplicate parameters
+ struct cil_list_item *curr_param;
+ cil_list_for_each(curr_param, macro->params) {
+ if (param->str == ((struct cil_param*)curr_param->data)->str) {
+ if (param->flavor == ((struct cil_param*)curr_param->data)->flavor) {
+ cil_log(CIL_ERR, "Duplicate parameter\n");
+ cil_destroy_param(param);
+ goto exit;
+ }
+ }
+ }
+
+ cil_list_append(macro->params, CIL_PARAM, param);
+
+ current_item = current_item->next;
+ }
+
+ /* we don't want the tree walker to walk the macro parameters (they were just handled above), so the subtree is deleted, and the next pointer of the
+ node containing the macro name is updated to point to the start of the macro content */
+ macro_content = parse_current->next->next->next;
+ cil_tree_subtree_destroy(parse_current->next->next);
+ parse_current->next->next = macro_content;
+ if (macro_content == NULL) {
+ /* No statements in macro and macro parameter list was last node */
+ parse_current->parent->cl_tail = parse_current->next;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)macro, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_MACRO);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad macro declaration");
+ cil_destroy_macro(macro);
+ cil_clear_node(ast_node);
+ return SEPOL_ERR;
+}
+
+void cil_destroy_macro(struct cil_macro *macro)
+{
+ if (macro == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(¯o->datum);
+ cil_symtab_array_destroy(macro->symtab);
+
+ if (macro->params != NULL) {
+ cil_list_destroy(¯o->params, 1);
+ }
+
+ free(macro);
+}
+
+int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_LIST | CIL_SYN_EMPTY_LIST | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_call *call = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_call_init(&call);
+
+ call->macro_str = parse_current->next->data;
+
+ if (parse_current->next->next != NULL) {
+ cil_tree_init(&call->args_tree);
+ cil_copy_ast(db, parse_current->next->next, call->args_tree->root);
+ }
+
+ ast_node->data = call;
+ ast_node->flavor = CIL_CALL;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad macro call");
+ cil_destroy_call(call);
+ return rc;
+}
+
+void cil_destroy_call(struct cil_call *call)
+{
+ if (call == NULL) {
+ return;
+ }
+
+ call->macro = NULL;
+
+ if (call->args_tree != NULL) {
+ cil_tree_destroy(&call->args_tree);
+ }
+
+ if (call->args != NULL) {
+ cil_list_destroy(&call->args, 1);
+ }
+
+ free(call);
+}
+
+void cil_destroy_args(struct cil_args *args)
+{
+ if (args == NULL) {
+ return;
+ }
+
+ if (args->arg_str != NULL) {
+ args->arg_str = NULL;
+ } else if (args->arg != NULL) {
+ struct cil_tree_node *node = args->arg->nodes->head->data;
+ switch (args->flavor) {
+ case CIL_NAME:
+ break;
+ case CIL_CATSET:
+ cil_destroy_catset((struct cil_catset *)args->arg);
+ free(node);
+ break;
+ case CIL_LEVEL:
+ cil_destroy_level((struct cil_level *)args->arg);
+ free(node);
+ break;
+ case CIL_LEVELRANGE:
+ cil_destroy_levelrange((struct cil_levelrange *)args->arg);
+ free(node);
+ break;
+ case CIL_IPADDR:
+ cil_destroy_ipaddr((struct cil_ipaddr *)args->arg);
+ free(node);
+ break;
+ case CIL_CLASSPERMISSION:
+ cil_destroy_classpermission((struct cil_classpermission *)args->arg);
+ free(node);
+ break;
+ default:
+ cil_log(CIL_ERR, "Destroying arg with the unexpected flavor=%d\n",args->flavor);
+ break;
+ }
+ }
+
+ args->param_str = NULL;
+ args->arg = NULL;
+
+ free(args);
+}
+
+int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_N_LISTS | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_optional *optional = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_optional_init(&optional);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)optional, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_OPTIONAL);
+ if (rc != SEPOL_OK)
+ goto exit;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad optional");
+ cil_destroy_optional(optional);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_optional(struct cil_optional *optional)
+{
+ if (optional == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&optional->datum);
+ free(optional);
+}
+
+int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_policycap *polcap = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_policycap_init(&polcap);
+
+ key = parse_current->next->data;
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)polcap, (hashtab_key_t)key, CIL_SYM_POLICYCAPS, CIL_POLICYCAP);
+ if (rc != SEPOL_OK)
+ goto exit;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad policycap statement");
+ cil_destroy_policycap(polcap);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_policycap(struct cil_policycap *polcap)
+{
+ if (polcap == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&polcap->datum);
+ free(polcap);
+}
+
+int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ char *key = NULL;
+ struct cil_ipaddr *ipaddr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_ipaddr_init(&ipaddr);
+
+ key = parse_current->next->data;
+
+ rc = cil_fill_ipaddr(parse_current->next->next, ipaddr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)ipaddr, (hashtab_key_t)key, CIL_SYM_IPADDRS, CIL_IPADDR);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad ipaddr statement");
+ cil_destroy_ipaddr(ipaddr);
+ cil_clear_node(ast_node);
+ return rc;
+}
+
+void cil_destroy_ipaddr(struct cil_ipaddr *ipaddr)
+{
+ if (ipaddr == NULL) {
+ return;
+ }
+
+ cil_symtab_datum_destroy(&ipaddr->datum);
+ free(ipaddr);
+}
+
+int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer)
+{
+ int rc = SEPOL_ERR;
+ char *endptr = NULL;
+ int val;
+
+ if (int_node == NULL || integer == NULL) {
+ goto exit;
+ }
+
+ errno = 0;
+ val = strtol(int_node->data, &endptr, 10);
+ if (errno != 0 || endptr == int_node->data || *endptr != '\0') {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ *integer = val;
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to create integer from string\n");
+ return rc;
+}
+
+int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer)
+{
+ int rc = SEPOL_ERR;
+ char *endptr = NULL;
+ uint64_t val;
+
+ if (int_node == NULL || integer == NULL) {
+ goto exit;
+ }
+
+ errno = 0;
+ val = strtoull(int_node->data, &endptr, 10);
+ if (errno != 0 || endptr == int_node->data || *endptr != '\0') {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ *integer = val;
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Failed to create integer from string\n");
+ return rc;
+}
+
+int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr)
+{
+ int rc = SEPOL_ERR;
+
+ if (addr_node == NULL || addr == NULL) {
+ goto exit;
+ }
+
+ if (addr_node->cl_head != NULL || addr_node->next != NULL) {
+ goto exit;
+ }
+
+ if (strchr(addr_node->data, '.') != NULL) {
+ addr->family = AF_INET;
+ } else {
+ addr->family = AF_INET6;
+ }
+
+ rc = inet_pton(addr->family, addr_node->data, &addr->ip);
+ if (rc != 1) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad ip address or netmask\n");
+ return rc;
+}
+
+int cil_fill_level(struct cil_tree_node *curr, struct cil_level *level)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ if (curr == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(curr, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ level->sens_str = curr->data;
+ if (curr->next != NULL) {
+ rc = cil_fill_cats(curr->next, &level->cats);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Bad level\n");
+ return rc;
+}
+
+int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats)
+{
+ int rc = SEPOL_ERR;
+
+ cil_cats_init(cats);
+
+ rc = cil_gen_expr(curr, CIL_CAT, &(*cats)->str_expr);
+ if (rc != SEPOL_OK) {
+ cil_destroy_cats(*cats);
+ }
+
+ return rc;
+}
+
+void cil_destroy_cats(struct cil_cats *cats)
+{
+ if (cats == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&cats->str_expr, CIL_TRUE);
+
+ cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+
+ free(cats);
+}
+int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_bounds *bounds = NULL;
+ int rc = SEPOL_ERR;
+
+ if (db == NULL || parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_bounds_init(&bounds);
+
+ bounds->parent_str = parse_current->next->data;
+ bounds->child_str = parse_current->next->next->data;
+
+ ast_node->data = bounds;
+
+ switch (flavor) {
+ case CIL_USER:
+ ast_node->flavor = CIL_USERBOUNDS;
+ break;
+ case CIL_ROLE:
+ ast_node->flavor = CIL_ROLEBOUNDS;
+ break;
+ case CIL_TYPE:
+ ast_node->flavor = CIL_TYPEBOUNDS;
+ break;
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad bounds declaration");
+ cil_destroy_bounds(bounds);
+ return rc;
+}
+
+void cil_destroy_bounds(struct cil_bounds *bounds)
+{
+ if (bounds == NULL) {
+ return;
+ }
+
+ free(bounds);
+}
+
+int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
+{
+ int rc = SEPOL_ERR;
+ struct cil_default *def = NULL;
+ char *object;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_default_init(&def);
+
+ def->flavor = flavor;
+
+ if (parse_current->next->cl_head == NULL) {
+ cil_list_init(&def->class_strs, CIL_CLASS);
+ cil_list_append(def->class_strs, CIL_STRING, parse_current->next->data);
+ rc = SEPOL_OK;
+ } else {
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASS, &def->class_strs);
+ }
+
+ object = parse_current->next->next->data;
+ if (object == CIL_KEY_SOURCE) {
+ def->object = CIL_DEFAULT_SOURCE;
+ } else if (object == CIL_KEY_TARGET) {
+ def->object = CIL_DEFAULT_TARGET;
+ } else {
+ cil_log(CIL_ERR,"Expected either 'source' or 'target'\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ ast_node->data = def;
+ ast_node->flavor = flavor;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", cil_node_to_string(parse_current));
+ cil_destroy_default(def);
+ return rc;
+}
+
+void cil_destroy_default(struct cil_default *def)
+{
+ if (def == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&def->class_strs, CIL_TRUE);
+
+ cil_list_destroy(&def->class_datums, CIL_FALSE);
+
+ free(def);
+}
+
+int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_defaultrange *def = NULL;
+ char *object;
+ char *range;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_defaultrange_init(&def);
+
+ if (parse_current->next->cl_head == NULL) {
+ cil_list_init(&def->class_strs, CIL_CLASS);
+ cil_list_append(def->class_strs, CIL_STRING, parse_current->next->data);
+ rc = SEPOL_OK;
+ } else {
+ rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASS, &def->class_strs);
+ }
+
+ object = parse_current->next->next->data;
+ range = parse_current->next->next->next->data;
+ if (object == CIL_KEY_SOURCE) {
+ if (range == CIL_KEY_LOW) {
+ def->object_range = CIL_DEFAULT_SOURCE_LOW;
+ } else if (range == CIL_KEY_HIGH) {
+ def->object_range = CIL_DEFAULT_SOURCE_HIGH;
+ } else if (range == CIL_KEY_LOW_HIGH) {
+ def->object_range = CIL_DEFAULT_SOURCE_LOW_HIGH;
+ } else {
+ cil_log(CIL_ERR,"Expected 'low', 'high', or 'low-high'\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else if (parse_current->next->next->data == CIL_KEY_TARGET) {
+ if (range == CIL_KEY_LOW) {
+ def->object_range = CIL_DEFAULT_TARGET_LOW;
+ } else if (range == CIL_KEY_HIGH) {
+ def->object_range = CIL_DEFAULT_TARGET_HIGH;
+ } else if (range == CIL_KEY_LOW_HIGH) {
+ def->object_range = CIL_DEFAULT_TARGET_LOW_HIGH;
+ } else {
+ cil_log(CIL_ERR,"Expected 'low', 'high', or 'low-high'\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR,"Expected either \'source\' or \'target\'\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ ast_node->data = def;
+ ast_node->flavor = CIL_DEFAULTRANGE;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad defaultrange declaration");
+ cil_destroy_defaultrange(def);
+ return rc;
+}
+
+void cil_destroy_defaultrange(struct cil_defaultrange *def)
+{
+ if (def == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&def->class_strs, CIL_TRUE);
+
+ cil_list_destroy(&def->class_datums, CIL_FALSE);
+
+ free(def);
+}
+
+int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_handleunknown *unknown = NULL;
+ char *unknown_key;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_handleunknown_init(&unknown);
+
+ unknown_key = parse_current->next->data;
+ if (unknown_key == CIL_KEY_HANDLEUNKNOWN_ALLOW) {
+ unknown->handle_unknown = SEPOL_ALLOW_UNKNOWN;
+ } else if (unknown_key == CIL_KEY_HANDLEUNKNOWN_DENY) {
+ unknown->handle_unknown = SEPOL_DENY_UNKNOWN;
+ } else if (unknown_key == CIL_KEY_HANDLEUNKNOWN_REJECT) {
+ unknown->handle_unknown = SEPOL_REJECT_UNKNOWN;
+ } else {
+ cil_log(CIL_ERR, "Expected either \'%s\', \'%s\', or \'%s\'\n", CIL_KEY_HANDLEUNKNOWN_ALLOW, CIL_KEY_HANDLEUNKNOWN_DENY, CIL_KEY_HANDLEUNKNOWN_REJECT);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ ast_node->data = unknown;
+ ast_node->flavor = CIL_HANDLEUNKNOWN;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad handleunknown");
+ cil_destroy_handleunknown(unknown);
+ return rc;
+}
+
+void cil_destroy_handleunknown(struct cil_handleunknown *unk)
+{
+ free(unk);
+}
+
+int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ int rc = SEPOL_ERR;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_mls *mls = NULL;
+
+ if (parse_current == NULL || ast_node == NULL) {
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cil_mls_init(&mls);
+
+ if (parse_current->next->data == CIL_KEY_CONDTRUE) {
+ mls->value = CIL_TRUE;
+ } else if (parse_current->next->data == CIL_KEY_CONDFALSE) {
+ mls->value = CIL_FALSE;
+ } else {
+ cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ ast_node->data = mls;
+ ast_node->flavor = CIL_MLS;
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(parse_current, CIL_ERR, "Bad mls");
+ cil_destroy_mls(mls);
+ return rc;
+}
+
+void cil_destroy_mls(struct cil_mls *mls)
+{
+ free(mls);
+}
+
+int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+ /* No need to check syntax, because this is auto generated */
+ struct cil_src_info *info = NULL;
+
+ cil_src_info_init(&info);
+
+ info->is_cil = (parse_current->next->data == CIL_KEY_SRC_CIL) ? CIL_TRUE : CIL_FALSE;
+ info->path = parse_current->next->next->data;
+
+ ast_node->data = info;
+ ast_node->flavor = CIL_SRC_INFO;
+
+ return SEPOL_OK;
+}
+
+void cil_destroy_src_info(struct cil_src_info *info)
+{
+ free(info);
+}
+
+int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args)
+{
+ struct cil_args_build *args = NULL;
+ struct cil_tree_node *ast_current = NULL;
+ struct cil_db *db = NULL;
+ struct cil_tree_node *ast_node = NULL;
+ struct cil_tree_node *macro = NULL;
+ struct cil_tree_node *boolif = NULL;
+ struct cil_tree_node *tunif = NULL;
+ struct cil_tree_node *in = NULL;
+ int rc = SEPOL_ERR;
+
+ if (parse_current == NULL || finished == NULL || extra_args == NULL) {
+ goto exit;
+ }
+
+ args = extra_args;
+ ast_current = args->ast;
+ db = args->db;
+ macro = args->macro;
+ boolif = args->boolif;
+ tunif = args->tunif;
+ in = args->in;
+
+ if (parse_current->parent->cl_head != parse_current) {
+ /* ignore anything that isn't following a parenthesis */
+ rc = SEPOL_OK;
+ goto exit;
+ } else if (parse_current->data == NULL) {
+ /* the only time parenthsis can immediately following parenthesis is if
+ * the parent is the root node */
+ if (parse_current->parent->parent == NULL) {
+ rc = SEPOL_OK;
+ } else {
+ cil_tree_log(parse_current, CIL_ERR, "Keyword expected after open parenthesis");
+ }
+ goto exit;
+ }
+
+ if (macro != NULL) {
+ if (parse_current->data == CIL_KEY_MACRO ||
+ parse_current->data == CIL_KEY_TUNABLE ||
+ parse_current->data == CIL_KEY_IN ||
+ parse_current->data == CIL_KEY_BLOCK ||
+ parse_current->data == CIL_KEY_BLOCKINHERIT ||
+ parse_current->data == CIL_KEY_BLOCKABSTRACT) {
+ rc = SEPOL_ERR;
+ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macros", (char *)parse_current->data);
+ goto exit;
+ }
+ }
+
+ if (boolif != NULL) {
+ if (parse_current->data != CIL_KEY_CONDTRUE &&
+ parse_current->data != CIL_KEY_CONDFALSE &&
+ parse_current->data != CIL_KEY_AUDITALLOW &&
+ parse_current->data != CIL_KEY_TUNABLEIF &&
+ parse_current->data != CIL_KEY_ALLOW &&
+ parse_current->data != CIL_KEY_DONTAUDIT &&
+ parse_current->data != CIL_KEY_TYPETRANSITION &&
+ parse_current->data != CIL_KEY_TYPECHANGE &&
+ parse_current->data != CIL_KEY_CALL) {
+ rc = SEPOL_ERR;
+ cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data);
+ if (((struct cil_booleanif*)boolif->data)->preserved_tunable) {
+ cil_log(CIL_ERR, "%s cannot be defined within tunableif statement (treated as a booleanif due to preserve-tunables)\n",
+ (char*)parse_current->data);
+ } else {
+ cil_log(CIL_ERR, "%s cannot be defined within booleanif statement\n",
+ (char*)parse_current->data);
+ }
+ goto exit;
+ }
+ }
+
+ if (tunif != NULL) {
+ if (parse_current->data == CIL_KEY_TUNABLE) {
+ rc = SEPOL_ERR;
+ cil_tree_log(parse_current, CIL_ERR, "Found tunable");
+ cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n");
+ goto exit;
+ }
+ }
+
+ if (in != NULL) {
+ if (parse_current->data == CIL_KEY_IN) {
+ rc = SEPOL_ERR;
+ cil_tree_log(parse_current, CIL_ERR, "Found in-statement");
+ cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n");
+ goto exit;
+ }
+ }
+
+ cil_tree_node_init(&ast_node);
+
+ ast_node->parent = ast_current;
+ ast_node->line = parse_current->line;
+ ast_node->hll_line = parse_current->hll_line;
+
+ if (parse_current->data == CIL_KEY_BLOCK) {
+ rc = cil_gen_block(db, parse_current, ast_node, 0);
+ } else if (parse_current->data == CIL_KEY_BLOCKINHERIT) {
+ rc = cil_gen_blockinherit(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_BLOCKABSTRACT) {
+ rc = cil_gen_blockabstract(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_IN) {
+ rc = cil_gen_in(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_CLASS) {
+ rc = cil_gen_class(db, parse_current, ast_node);
+ // To avoid parsing list of perms again
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CLASSORDER) {
+ rc = cil_gen_classorder(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_MAP_CLASS) {
+ rc = cil_gen_map_class(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CLASSMAPPING) {
+ rc = cil_gen_classmapping(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CLASSPERMISSION) {
+ rc = cil_gen_classpermission(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CLASSPERMISSIONSET) {
+ rc = cil_gen_classpermissionset(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_COMMON) {
+ rc = cil_gen_common(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CLASSCOMMON) {
+ rc = cil_gen_classcommon(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_SID) {
+ rc = cil_gen_sid(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SIDCONTEXT) {
+ rc = cil_gen_sidcontext(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SIDORDER) {
+ rc = cil_gen_sidorder(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_USER) {
+ rc = cil_gen_user(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_USERATTRIBUTE) {
+ rc = cil_gen_userattribute(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_USERATTRIBUTESET) {
+ rc = cil_gen_userattributeset(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_USERLEVEL) {
+ rc = cil_gen_userlevel(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_USERRANGE) {
+ rc = cil_gen_userrange(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_USERBOUNDS) {
+ rc = cil_gen_bounds(db, parse_current, ast_node, CIL_USER);
+ } else if (parse_current->data == CIL_KEY_USERPREFIX) {
+ rc = cil_gen_userprefix(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_SELINUXUSER) {
+ rc = cil_gen_selinuxuser(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SELINUXUSERDEFAULT) {
+ rc = cil_gen_selinuxuserdefault(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_TYPE) {
+ rc = cil_gen_type(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_TYPEATTRIBUTE) {
+ rc = cil_gen_typeattribute(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_TYPEATTRIBUTESET) {
+ rc = cil_gen_typeattributeset(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_TYPEALIAS) {
+ rc = cil_gen_alias(db, parse_current, ast_node, CIL_TYPEALIAS);
+ } else if (parse_current->data == CIL_KEY_TYPEALIASACTUAL) {
+ rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_TYPEALIASACTUAL);
+ } else if (parse_current->data == CIL_KEY_TYPEBOUNDS) {
+ rc = cil_gen_bounds(db, parse_current, ast_node, CIL_TYPE);
+ } else if (parse_current->data == CIL_KEY_TYPEPERMISSIVE) {
+ rc = cil_gen_typepermissive(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_RANGETRANSITION) {
+ rc = cil_gen_rangetransition(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_ROLE) {
+ rc = cil_gen_role(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_USERROLE) {
+ rc = cil_gen_userrole(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_ROLETYPE) {
+ rc = cil_gen_roletype(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_ROLETRANSITION) {
+ rc = cil_gen_roletransition(parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_ROLEALLOW) {
+ rc = cil_gen_roleallow(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_ROLEATTRIBUTE) {
+ rc = cil_gen_roleattribute(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_ROLEATTRIBUTESET) {
+ rc = cil_gen_roleattributeset(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_ROLEBOUNDS) {
+ rc = cil_gen_bounds(db, parse_current, ast_node, CIL_ROLE);
+ } else if (parse_current->data == CIL_KEY_BOOL) {
+ rc = cil_gen_bool(db, parse_current, ast_node, CIL_FALSE);
+ } else if (parse_current->data == CIL_KEY_BOOLEANIF) {
+ rc = cil_gen_boolif(db, parse_current, ast_node, CIL_FALSE);
+ } else if(parse_current->data == CIL_KEY_TUNABLE) {
+ if (db->preserve_tunables) {
+ rc = cil_gen_bool(db, parse_current, ast_node, CIL_TRUE);
+ } else {
+ rc = cil_gen_tunable(db, parse_current, ast_node);
+ }
+ } else if (parse_current->data == CIL_KEY_TUNABLEIF) {
+ if (db->preserve_tunables) {
+ rc = cil_gen_boolif(db, parse_current, ast_node, CIL_TRUE);
+ } else {
+ rc = cil_gen_tunif(db, parse_current, ast_node);
+ }
+ } else if (parse_current->data == CIL_KEY_CONDTRUE) {
+ rc = cil_gen_condblock(db, parse_current, ast_node, CIL_CONDTRUE);
+ } else if (parse_current->data == CIL_KEY_CONDFALSE) {
+ rc = cil_gen_condblock(db, parse_current, ast_node, CIL_CONDFALSE);
+ } else if (parse_current->data == CIL_KEY_ALLOW) {
+ rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_ALLOWED);
+ // So that the object and perms lists do not get parsed again
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_AUDITALLOW) {
+ rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_AUDITALLOW);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DONTAUDIT) {
+ rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_DONTAUDIT);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_NEVERALLOW) {
+ rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_ALLOWX) {
+ rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_ALLOWED);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_AUDITALLOWX) {
+ rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_AUDITALLOW);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DONTAUDITX) {
+ rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_DONTAUDIT);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_NEVERALLOWX) {
+ rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_PERMISSIONX) {
+ rc = cil_gen_permissionx(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_TYPETRANSITION) {
+ rc = cil_gen_typetransition(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_TYPECHANGE) {
+ rc = cil_gen_type_rule(parse_current, ast_node, CIL_TYPE_CHANGE);
+ } else if (parse_current->data == CIL_KEY_TYPEMEMBER) {
+ rc = cil_gen_type_rule(parse_current, ast_node, CIL_TYPE_MEMBER);
+ } else if (parse_current->data == CIL_KEY_SENSITIVITY) {
+ rc = cil_gen_sensitivity(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_SENSALIAS) {
+ rc = cil_gen_alias(db, parse_current, ast_node, CIL_SENSALIAS);
+ } else if (parse_current->data == CIL_KEY_SENSALIASACTUAL) {
+ rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_SENSALIASACTUAL);
+ } else if (parse_current->data == CIL_KEY_CATEGORY) {
+ rc = cil_gen_category(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_CATALIAS) {
+ rc = cil_gen_alias(db, parse_current, ast_node, CIL_CATALIAS);
+ } else if (parse_current->data == CIL_KEY_CATALIASACTUAL) {
+ rc = cil_gen_aliasactual(db, parse_current, ast_node, CIL_CATALIASACTUAL);
+ } else if (parse_current->data == CIL_KEY_CATSET) {
+ rc = cil_gen_catset(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CATORDER) {
+ rc = cil_gen_catorder(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SENSITIVITYORDER) {
+ rc = cil_gen_sensitivityorder(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SENSCAT) {
+ rc = cil_gen_senscat(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_LEVEL) {
+ rc = cil_gen_level(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_LEVELRANGE) {
+ rc = cil_gen_levelrange(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CONSTRAIN) {
+ rc = cil_gen_constrain(db, parse_current, ast_node, CIL_CONSTRAIN);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_MLSCONSTRAIN) {
+ rc = cil_gen_constrain(db, parse_current, ast_node, CIL_MLSCONSTRAIN);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_VALIDATETRANS) {
+ rc = cil_gen_validatetrans(db, parse_current, ast_node, CIL_VALIDATETRANS);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_MLSVALIDATETRANS) {
+ rc = cil_gen_validatetrans(db, parse_current, ast_node, CIL_MLSVALIDATETRANS);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_CONTEXT) {
+ rc = cil_gen_context(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_FILECON) {
+ rc = cil_gen_filecon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_PORTCON) {
+ rc = cil_gen_portcon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_NODECON) {
+ rc = cil_gen_nodecon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_GENFSCON) {
+ rc = cil_gen_genfscon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_NETIFCON) {
+ rc = cil_gen_netifcon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_PIRQCON) {
+ rc = cil_gen_pirqcon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_IOMEMCON) {
+ rc = cil_gen_iomemcon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_IOPORTCON) {
+ rc = cil_gen_ioportcon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_PCIDEVICECON) {
+ rc = cil_gen_pcidevicecon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DEVICETREECON) {
+ rc = cil_gen_devicetreecon(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_FSUSE) {
+ rc = cil_gen_fsuse(db, parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_MACRO) {
+ rc = cil_gen_macro(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_CALL) {
+ rc = cil_gen_call(db, parse_current, ast_node);
+ *finished = 1;
+ } else if (parse_current->data == CIL_KEY_POLICYCAP) {
+ rc = cil_gen_policycap(db, parse_current, ast_node);
+ *finished = 1;
+ } else if (parse_current->data == CIL_KEY_OPTIONAL) {
+ rc = cil_gen_optional(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_IPADDR) {
+ rc = cil_gen_ipaddr(db, parse_current, ast_node);
+ } else if (parse_current->data == CIL_KEY_DEFAULTUSER) {
+ rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTUSER);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DEFAULTROLE) {
+ rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTROLE);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DEFAULTTYPE) {
+ rc = cil_gen_default(parse_current, ast_node, CIL_DEFAULTTYPE);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_DEFAULTRANGE) {
+ rc = cil_gen_defaultrange(parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_HANDLEUNKNOWN) {
+ rc = cil_gen_handleunknown(parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_MLS) {
+ rc = cil_gen_mls(parse_current, ast_node);
+ *finished = CIL_TREE_SKIP_NEXT;
+ } else if (parse_current->data == CIL_KEY_SRC_INFO) {
+ rc = cil_gen_src_info(parse_current, ast_node);
+ } else {
+ cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data);
+ rc = SEPOL_ERR;
+ }
+
+ if (rc == SEPOL_OK) {
+ if (ast_current->cl_head == NULL) {
+ if (ast_current->flavor == CIL_MACRO) {
+ args->macro = ast_current;
+ }
+
+ if (ast_current->flavor == CIL_BOOLEANIF) {
+ args->boolif = ast_current;
+ }
+
+ if (ast_current->flavor == CIL_TUNABLEIF) {
+ args->tunif = ast_current;
+ }
+
+ if (ast_current->flavor == CIL_IN) {
+ args->in = ast_current;
+ }
+
+ ast_current->cl_head = ast_node;
+ } else {
+ ast_current->cl_tail->next = ast_node;
+ }
+ ast_current->cl_tail = ast_node;
+ ast_current = ast_node;
+ args->ast = ast_current;
+ } else {
+ cil_tree_node_destroy(&ast_node);
+ }
+
+exit:
+ return rc;
+}
+
+int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *ast = NULL;
+ struct cil_args_build *args = NULL;
+
+ if (extra_args == NULL) {
+ goto exit;
+ }
+
+ args = extra_args;
+ ast = args->ast;
+
+ if (ast->flavor == CIL_ROOT) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ args->ast = ast->parent;
+
+ if (ast->flavor == CIL_MACRO) {
+ args->macro = NULL;
+ }
+
+ if (ast->flavor == CIL_BOOLEANIF) {
+ args->boolif = NULL;
+ }
+
+ if (ast->flavor == CIL_TUNABLEIF) {
+ args->tunif = NULL;
+ }
+
+ if (ast->flavor == CIL_IN) {
+ args->in = NULL;
+ }
+
+ // At this point we no longer have any need for parse_current or any of its
+ // siblings; they have all been converted to the appropriate AST node. The
+ // full parse tree will get deleted elsewhere, but in an attempt to
+ // minimize memory useage (of which the parse tree uses alot), start
+ // deleting the parts we don't need now.
+ cil_tree_children_destroy(parse_current->parent);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_build extra_args;
+
+ if (db == NULL || parse_tree == NULL || ast == NULL) {
+ goto exit;
+ }
+
+ extra_args.ast = ast;
+ extra_args.db = db;
+ extra_args.macro = NULL;
+ extra_args.boolif = NULL;
+ extra_args.tunif = NULL;
+ extra_args.in = NULL;
+
+ rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
new file mode 100644
index 0000000..825029e
--- /dev/null
+++ b/libsepol/cil/src/cil_build_ast.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_BUILD_AST_H_
+#define CIL_BUILD_AST_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor);
+int cil_parse_to_list(struct cil_tree_node *parse_cl_head, struct cil_list *ast_cl, enum cil_flavor flavor);
+
+int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract);
+void cil_destroy_block(struct cil_block *block);
+int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_blockinherit(struct cil_blockinherit *inherit);
+int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_blockabstract(struct cil_blockabstract *abstract);
+int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_in(struct cil_in *in);
+int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_class(struct cil_class *class);
+int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classorder(struct cil_classorder *classorder);
+int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
+void cil_destroy_perm(struct cil_perm *perm);
+int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
+int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perm_strs);
+int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp);
+void cil_destroy_classperms(struct cil_classperms *cp);
+void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set);
+void cil_destroy_classperms_set(struct cil_classperms_set *cp_set);
+int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **expr_list);
+void cil_destroy_classperms_list(struct cil_list **cp_list);
+int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classpermission(struct cil_classpermission *cp);
+int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classpermissionset(struct cil_classpermissionset *cps);
+int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classmapping(struct cil_classmapping *mapping);
+int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_classcommon(struct cil_classcommon *clscom);
+int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sid(struct cil_sid *sid);
+int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sidcontext(struct cil_sidcontext *sidcon);
+int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sidorder(struct cil_sidorder *sidorder);
+int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_user(struct cil_user *user);
+int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userattribute(struct cil_userattribute *attr);
+int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userattributeset(struct cil_userattributeset *attrset);
+int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userlevel(struct cil_userlevel *usrlvl);
+int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userrange(struct cil_userrange *userrange);
+int cil_gen_userbounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userprefix(struct cil_userprefix *userprefix);
+int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser);
+int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_role(struct cil_role *role);
+int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roletype(struct cil_roletype *roletype);
+int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_userrole(struct cil_userrole *userrole);
+int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roletransition(struct cil_roletransition *roletrans);
+int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleallow(struct cil_roleallow *roleallow);
+int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleattribute(struct cil_roleattribute *role);
+int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset);
+int cil_gen_rolebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+void cil_destroy_avrule(struct cil_avrule *rule);
+int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_permissionx(struct cil_permissionx *permx);
+int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
+void cil_destroy_type_rule(struct cil_type_rule *rule);
+int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_type(struct cil_type *type);
+int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typeattribute(struct cil_typeattribute *type);
+int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif);
+void cil_destroy_bool(struct cil_bool *boolean);
+int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_tunable(struct cil_tunable *tunable);
+int cil_gen_constrain_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
+int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
+int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunable_if);
+void cil_destroy_boolif(struct cil_booleanif *bif);
+int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_tunif(struct cil_tunableif *tif);
+int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_condblock(struct cil_condblock *cb);
+int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_alias(struct cil_alias *alias);
+int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual);
+int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typeattributeset(struct cil_typeattributeset *attrtypes);
+int cil_gen_typebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_typepermissive(struct cil_typepermissive *typeperm);
+int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_name(struct cil_name *name);
+void cil_destroy_typetransition(struct cil_nametypetransition *nametypetrans);
+int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_rangetransition(struct cil_rangetransition *rangetrans);
+int cil_gen_sensitivity(struct cil_db *idb, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sensitivity(struct cil_sens *sens);
+int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_category(struct cil_cat *cat);
+int cil_set_to_list(struct cil_tree_node *parse_current, struct cil_list *ast_cl);
+void cil_destroy_catset(struct cil_catset *catset);
+int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_catorder(struct cil_catorder *catorder);
+int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_sensitivityorder(struct cil_sensorder *sensorder);
+int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_senscat(struct cil_senscat *senscat);
+int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_level(struct cil_level *level);
+int cil_fill_levelrange(struct cil_tree_node *low, struct cil_levelrange *lvlrange);
+int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_levelrange(struct cil_levelrange *lvlrange);
+void cil_destroy_constrain_node(struct cil_tree_node *cons_node);
+int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_constrain(struct cil_constrain *cons);
+int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_validatetrans(struct cil_validatetrans *validtrans);
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
+int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_context(struct cil_context *context);
+int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_filecon(struct cil_filecon *filecon);
+int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_portcon(struct cil_portcon *portcon);
+int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_nodecon(struct cil_nodecon *nodecon);
+int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_genfscon(struct cil_genfscon *genfscon);
+int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_netifcon(struct cil_netifcon *netifcon);
+int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_pirqcon(struct cil_pirqcon *pirqcon);
+int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_iomemcon(struct cil_iomemcon *iomemcon);
+int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ioportcon(struct cil_ioportcon *ioportcon);
+int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_pcidevicecon(struct cil_pcidevicecon *pcidevicecon);
+int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_devicetreecon(struct cil_devicetreecon *devicetreecon);
+int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_fsuse(struct cil_fsuse *fsuse);
+void cil_destroy_param(struct cil_param *param);
+int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_macro(struct cil_macro *macro);
+int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_call(struct cil_call *call);
+void cil_destroy_args(struct cil_args *args);
+int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_optional(struct cil_optional *optional);
+int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_policycap(struct cil_policycap *polcap);
+int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ipaddr(struct cil_ipaddr *ipaddr);
+int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_bounds(struct cil_bounds *bounds);
+int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
+void cil_destroy_default(struct cil_default *def);
+int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_handleunknown(struct cil_handleunknown *unk);
+int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_mls(struct cil_mls *mls);
+int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_defaultrange(struct cil_defaultrange *def);
+int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_src_info(struct cil_src_info *info);
+
+int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats);
+void cil_destroy_cats(struct cil_cats *cats);
+int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
+int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer);
+int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer);
+int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr);
+int cil_fill_level(struct cil_tree_node *sens, struct cil_level *level);
+
+int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast);
+
+#endif /* CIL_BUILD_AST_H_ */
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
new file mode 100644
index 0000000..5debd0d
--- /dev/null
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -0,0 +1,2087 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+#include "cil_copy_ast.h"
+#include "cil_build_ast.h"
+#include "cil_strpool.h"
+
+struct cil_args_copy {
+ struct cil_tree_node *dest;
+ struct cil_db *db;
+};
+
+void cil_copy_list(struct cil_list *data, struct cil_list **copy)
+{
+ struct cil_list *new;
+ struct cil_list_item *orig_item;
+
+ cil_list_init(&new, data->flavor);
+
+ cil_list_for_each(orig_item, data) {
+ switch (orig_item->flavor) {
+ case CIL_STRING:
+ cil_list_append(new, CIL_STRING, orig_item->data);
+ break;
+ case CIL_LIST: {
+ struct cil_list *new_sub = NULL;
+ cil_copy_list((struct cil_list*)orig_item->data, &new_sub);
+ cil_list_append(new, CIL_LIST, new_sub);
+ break;
+ }
+ case CIL_PARAM: {
+ struct cil_param *po = orig_item->data;
+ struct cil_param *pn;
+ cil_param_init(&pn);
+ pn->str = po->str;
+ pn->flavor = po->flavor;
+ cil_list_append(new, CIL_PARAM, pn);
+ }
+ break;
+
+ default:
+ cil_list_append(new, orig_item->flavor, orig_item->data);
+ break;
+ }
+ }
+
+ *copy = new;
+}
+
+int cil_copy_node(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ char *new = NULL;
+
+ if (data != NULL) {
+ new = data;
+ }
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_block(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_block *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_block *new;
+ cil_block_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_blockabstract(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_blockabstract *orig = data;
+ struct cil_blockabstract *new = NULL;
+
+ cil_blockabstract_init(&new);
+
+ new->block_str = orig->block_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_blockinherit(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_blockinherit *orig = data;
+ struct cil_blockinherit *new = NULL;
+
+ cil_blockinherit_init(&new);
+
+ new->block_str = orig->block_str;
+ new->block = orig->block;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_policycap(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_policycap *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_policycap *new;
+ cil_policycap_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_perm(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_perm *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_perm *new;
+ cil_perm_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+void cil_copy_classperms(struct cil_classperms *orig, struct cil_classperms **new)
+{
+ cil_classperms_init(new);
+ (*new)->class_str = orig->class_str;
+ cil_copy_list(orig->perm_strs, &((*new)->perm_strs));
+}
+
+void cil_copy_classperms_set(struct cil_classperms_set *orig, struct cil_classperms_set **new)
+{
+ cil_classperms_set_init(new);
+ (*new)->set_str = orig->set_str;
+}
+
+void cil_copy_classperms_list(struct cil_list *orig, struct cil_list **new)
+{
+ struct cil_list_item *orig_item;
+
+ if (orig == NULL) {
+ return;
+ }
+
+ cil_list_init(new, CIL_LIST_ITEM);
+ cil_list_for_each(orig_item, orig) {
+ if (orig_item->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp;
+ cil_copy_classperms(orig_item->data, &cp);
+ cil_list_append(*new, CIL_CLASSPERMS, cp);
+ } else {
+ struct cil_classperms_set *cp_set;
+ cil_copy_classperms_set(orig_item->data, &cp_set);
+ cil_list_append(*new, CIL_CLASSPERMS_SET, cp_set);
+ }
+ }
+}
+
+int cil_copy_classmapping(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_classmapping *orig = data;
+ struct cil_classmapping *new = NULL;
+
+ cil_classmapping_init(&new);
+
+ new->map_class_str = orig->map_class_str;
+ new->map_perm_str = orig->map_perm_str;
+
+ cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_class(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_class *orig = data;
+ struct cil_class *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_class: class cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_class_init(&new);
+
+ new->common = NULL;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_classorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_classorder *orig = data;
+ struct cil_classorder *new = NULL;
+
+ cil_classorder_init(&new);
+ if (orig->class_list_str != NULL) {
+ cil_copy_list(orig->class_list_str, &new->class_list_str);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_classpermission *orig = data;
+ struct cil_classpermission *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ if (key != NULL) {
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "classpermission cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ cil_classpermission_init(&new);
+
+ cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_classpermissionset *orig = data;
+ struct cil_classpermissionset *new = NULL;
+
+ cil_classpermissionset_init(&new);
+
+ new->set_str = orig->set_str;
+
+ cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_classcommon(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_classcommon *orig = data;
+ struct cil_classcommon *new = NULL;
+
+ cil_classcommon_init(&new);
+
+ new->class_str = orig->class_str;
+ new->common_str = orig->common_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_sid(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_sid *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_sid *new;
+ cil_sid_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_sidcontext *orig = data;
+ struct cil_sidcontext *new = NULL;
+
+ cil_sidcontext_init(&new);
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_sidorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_sidorder *orig = data;
+ struct cil_sidorder *new = NULL;
+
+ cil_sidorder_init(&new);
+ if (orig->sid_list_str != NULL) {
+ cil_copy_list(orig->sid_list_str, &new->sid_list_str);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_user(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_user *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_user *new;
+ cil_user_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_userattribute *orig = data;
+ struct cil_userattribute *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ cil_userattribute_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_userattributeset *orig = data;
+ struct cil_userattributeset *new = NULL;
+
+ cil_userattributeset_init(&new);
+
+ new->attr_str = orig->attr_str;
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userrole(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_userrole *orig = data;
+ struct cil_userrole *new = NULL;
+
+ cil_userrole_init(&new);
+
+ new->user_str = orig->user_str;
+ new->role_str = orig->role_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_userlevel *orig = data;
+ struct cil_userlevel *new = NULL;
+
+ cil_userlevel_init(&new);
+
+ new->user_str = orig->user_str;
+
+ if (orig->level_str != NULL) {
+ new->level_str = orig->level_str;
+ } else {
+ cil_copy_fill_level(db, orig->level, &new->level);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userrange(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_userrange *orig = data;
+ struct cil_userrange *new = NULL;
+
+ cil_userrange_init(&new);
+
+ new->user_str = orig->user_str;
+
+ if (orig->range_str != NULL) {
+ new->range_str = orig->range_str;
+ } else {
+ cil_levelrange_init(&new->range);
+ cil_copy_fill_levelrange(db, orig->range, new->range);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_userprefix(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_userprefix *orig = data;
+ struct cil_userprefix *new = NULL;
+
+ cil_userprefix_init(&new);
+
+ new->user_str = orig->user_str;
+ new->prefix_str = orig->prefix_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_role(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_role *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_role *new;
+ cil_role_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_roletype(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_roletype *orig = data;
+ struct cil_roletype *new = NULL;
+
+ cil_roletype_init(&new);
+
+ new->role_str = orig->role_str;
+ new->type_str = orig->type_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_roleattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_roleattribute *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_roleattribute *new;
+ cil_roleattribute_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_roleattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_roleattributeset *orig = data;
+ struct cil_roleattributeset *new = NULL;
+
+ cil_roleattributeset_init(&new);
+
+ new->attr_str = orig->attr_str;
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_roleallow(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_roleallow *orig = data;
+ struct cil_roleallow *new = NULL;
+
+ cil_roleallow_init(&new);
+
+ new->src_str = orig->src_str;
+ new->tgt_str = orig->tgt_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_type(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_type *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_type *new;
+ cil_type_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_typepermissive(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_typepermissive *orig = data;
+ struct cil_typepermissive *new = NULL;
+
+ cil_typepermissive_init(&new);
+
+ new->type_str = orig->type_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_typeattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_typeattribute *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_typeattribute *new;
+ cil_typeattribute_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_typeattributeset *orig = data;
+ struct cil_typeattributeset *new = NULL;
+
+ cil_typeattributeset_init(&new);
+
+ new->attr_str = orig->attr_str;
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_alias *orig = data;
+ struct cil_alias *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_alias: alias cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_alias_init(&new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_aliasactual(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused))symtab_t *symtab)
+{
+ struct cil_aliasactual *orig = data;
+ struct cil_aliasactual *new = NULL;
+
+ cil_aliasactual_init(&new);
+
+ new->alias_str = orig->alias_str;
+ new->actual_str = orig->actual_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_roletransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_roletransition *orig = data;
+ struct cil_roletransition *new = NULL;
+
+ cil_roletransition_init(&new);
+
+ new->src_str = orig->src_str;
+ new->tgt_str = orig->tgt_str;
+ new->obj_str = orig->obj_str;
+ new->result_str = orig->result_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_nametypetransition(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_nametypetransition *orig = data;
+ struct cil_nametypetransition *new = NULL;
+
+ cil_nametypetransition_init(&new);
+
+ new->src_str = orig->src_str;
+ new->tgt_str = orig->tgt_str;
+ new->obj_str = orig->obj_str;
+ new->name_str = orig->name_str;
+ new->result_str = orig->result_str;
+
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_rangetransition(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_rangetransition *orig = data;
+ struct cil_rangetransition *new = NULL;
+
+ cil_rangetransition_init(&new);
+
+ new->src_str = orig->src_str;
+ new->exec_str = orig->exec_str;
+ new->obj_str = orig->obj_str;
+
+ if (orig->range_str != NULL) {
+ new->range_str = orig->range_str;
+ } else {
+ cil_levelrange_init(&new->range);
+ cil_copy_fill_levelrange(db, orig->range, new->range);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_bool(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_bool *orig = data;
+ struct cil_bool *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_bool: boolean cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_bool_init(&new);
+ new->value = orig->value;
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_tunable(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_tunable *orig = data;
+ struct cil_tunable *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_tunable: tunable cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_tunable_init(&new);
+ new->value = orig->value;
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+void cil_copy_fill_permissionx(struct cil_db *db, struct cil_permissionx *orig, struct cil_permissionx *new)
+{
+ new->kind = orig->kind;
+ new->obj_str = orig->obj_str;
+ cil_copy_expr(db, orig->expr_str, &new->expr_str);
+}
+
+int cil_copy_avrule(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_avrule *orig = data;
+ struct cil_avrule *new = NULL;
+
+ cil_avrule_init(&new);
+
+ new->is_extended = orig->is_extended;
+ new->rule_kind = orig->rule_kind;
+ new->src_str = orig->src_str;
+ new->tgt_str = orig->tgt_str;
+
+ if (!new->is_extended) {
+ cil_copy_classperms_list(orig->perms.classperms, &new->perms.classperms);
+ } else {
+ if (new->perms.x.permx_str != NULL) {
+ new->perms.x.permx_str = orig->perms.x.permx_str;
+ } else {
+ cil_permissionx_init(&new->perms.x.permx);
+ cil_copy_fill_permissionx(db, orig->perms.x.permx, new->perms.x.permx);
+ }
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_permissionx(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_permissionx *orig = data;
+ struct cil_permissionx *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_permissionx: permissionx cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_permissionx_init(&new);
+ cil_copy_fill_permissionx(db, orig, new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_type_rule(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_type_rule *orig = data;
+ struct cil_type_rule *new = NULL;
+
+ cil_type_rule_init(&new);
+
+ new->rule_kind = orig->rule_kind;
+ new->src_str = orig->src_str;
+ new->tgt_str = orig->tgt_str;
+ new->obj_str = orig->obj_str;
+ new->result_str = orig->result_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_sens(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_sens *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_sens *new;
+ cil_sens_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_cat(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_cat *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_cat *new;
+ cil_cat_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+void cil_copy_cats(struct cil_db *db, struct cil_cats *orig, struct cil_cats **new)
+{
+ cil_cats_init(new);
+ cil_copy_expr(db, orig->str_expr, &(*new)->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &(*new)->datum_expr);
+}
+
+int cil_copy_catset(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_catset *orig = data;
+ struct cil_catset *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_catset: categoryset cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_catset_init(&new);
+
+ cil_copy_cats(db, orig->cats, &new->cats);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_senscat(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_senscat *orig = data;
+ struct cil_senscat *new = NULL;
+
+ cil_senscat_init(&new);
+
+ new->sens_str = orig->sens_str;
+
+ cil_copy_cats(db, orig->cats, &new->cats);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_catorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_catorder *orig = data;
+ struct cil_catorder *new = NULL;
+
+ cil_catorder_init(&new);
+ if (orig->cat_list_str != NULL) {
+ cil_copy_list(orig->cat_list_str, &new->cat_list_str);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_sensitivityorder(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_sensorder *orig = data;
+ struct cil_sensorder *new = NULL;
+
+ cil_sensorder_init(&new);
+ if (orig->sens_list_str != NULL) {
+ cil_copy_list(orig->sens_list_str, &new->sens_list_str);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+void cil_copy_fill_level(struct cil_db *db, struct cil_level *orig, struct cil_level **new)
+{
+ cil_level_init(new);
+
+ (*new)->sens_str = orig->sens_str;
+
+ if (orig->cats != NULL) {
+ cil_copy_cats(db, orig->cats, &(*new)->cats);
+ }
+}
+
+int cil_copy_level(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_level *orig = data;
+ struct cil_level *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ if (key != NULL) {
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_level: level cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ cil_copy_fill_level(db, orig, &new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+void cil_copy_fill_levelrange(struct cil_db *db, struct cil_levelrange *data, struct cil_levelrange *new)
+{
+ if (data->low_str != NULL) {
+ new->low_str = data->low_str;
+ } else {
+ cil_copy_fill_level(db, data->low, &new->low);
+ }
+
+ if (data->high_str != NULL) {
+ new->high_str = data->high_str;
+ } else {
+ cil_copy_fill_level(db, data->high, &new->high);
+ }
+}
+
+int cil_copy_levelrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_levelrange *orig = data;
+ struct cil_levelrange *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ if (key != NULL) {
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_levelrange: levelrange cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ cil_levelrange_init(&new);
+ cil_copy_fill_levelrange(db, orig, new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+void cil_copy_fill_context(struct cil_db *db, struct cil_context *data, struct cil_context *new)
+{
+ new->user_str = data->user_str;
+ new->role_str = data->role_str;
+ new->type_str = data->type_str;
+
+ if (data->range_str != NULL) {
+ new->range_str = data->range_str;
+ } else {
+ cil_levelrange_init(&new->range);
+ cil_copy_fill_levelrange(db, data->range, new->range);
+ }
+}
+
+int cil_copy_context(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_context *orig = data;
+ struct cil_context *new = NULL;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ if (key != NULL) {
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_context: context cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ cil_context_init(&new);
+ cil_copy_fill_context(db, orig, new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_netifcon *orig = data;
+ struct cil_netifcon *new = NULL;
+
+ cil_netifcon_init(&new);
+
+ new->interface_str = orig->interface_str;
+
+ if (orig->if_context_str != NULL) {
+ new->if_context_str = orig->if_context_str;
+ } else {
+ cil_context_init(&new->if_context);
+ cil_copy_fill_context(db, orig->if_context, new->if_context);
+ }
+
+ if (orig->packet_context_str != NULL) {
+ new->packet_context_str = orig->packet_context_str;
+ } else {
+ cil_context_init(&new->packet_context);
+ cil_copy_fill_context(db, orig->packet_context, new->packet_context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_genfscon *orig = data;
+ struct cil_genfscon *new = NULL;
+
+ cil_genfscon_init(&new);
+
+ new->fs_str = orig->fs_str;
+ new->path_str = orig->path_str;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_filecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_filecon *orig = data;
+ struct cil_filecon *new = NULL;
+
+ cil_filecon_init(&new);
+
+ new->path_str = orig->path_str;
+ new->type = orig->type;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else if (orig->context != NULL) {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_nodecon *orig = data;
+ struct cil_nodecon *new = NULL;
+
+ cil_nodecon_init(&new);
+
+ if (orig->addr_str != NULL) {
+ new->addr_str = orig->addr_str;
+ } else {
+ cil_ipaddr_init(&new->addr);
+ cil_copy_fill_ipaddr(orig->addr, new->addr);
+ }
+
+ if (orig->mask_str != NULL) {
+ new->mask_str = orig->mask_str;
+ } else {
+ cil_ipaddr_init(&new->mask);
+ cil_copy_fill_ipaddr(orig->mask, new->mask);
+ }
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_portcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_portcon *orig = data;
+ struct cil_portcon *new = NULL;
+
+ cil_portcon_init(&new);
+
+ new->proto = orig->proto;
+ new->port_low = orig->port_low;
+ new->port_high = orig->port_high;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_pirqcon *orig = data;
+ struct cil_pirqcon *new = NULL;
+
+ cil_pirqcon_init(&new);
+
+ new->pirq = orig->pirq;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_iomemcon *orig = data;
+ struct cil_iomemcon *new = NULL;
+
+ cil_iomemcon_init(&new);
+
+ new->iomem_low = orig->iomem_low;
+ new->iomem_high = orig->iomem_high;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_ioportcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_ioportcon *orig = data;
+ struct cil_ioportcon *new = NULL;
+
+ cil_ioportcon_init(&new);
+
+ new->ioport_low = orig->ioport_low;
+ new->ioport_high = orig->ioport_high;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_pcidevicecon *orig = data;
+ struct cil_pcidevicecon *new = NULL;
+
+ cil_pcidevicecon_init(&new);
+
+ new->dev = orig->dev;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_devicetreecon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_devicetreecon *orig = data;
+ struct cil_devicetreecon *new = NULL;
+
+ cil_devicetreecon_init(&new);
+
+ new->path = orig->path;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_fsuse(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_fsuse *orig = data;
+ struct cil_fsuse *new = NULL;
+
+ cil_fsuse_init(&new);
+
+ new->type = orig->type;
+ new->fs_str = orig->fs_str;
+
+ if (orig->context_str != NULL) {
+ new->context_str = orig->context_str;
+ } else {
+ cil_context_init(&new->context);
+ cil_copy_fill_context(db, orig->context, new->context);
+ }
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_expr(struct cil_db *db, struct cil_list *orig, struct cil_list **new)
+{
+ struct cil_list_item *curr;
+
+ if (orig == NULL) {
+ *new = NULL;
+ return SEPOL_OK;
+ }
+
+ cil_list_init(new, orig->flavor);
+
+ cil_list_for_each(curr, orig) {
+ switch (curr->flavor) {
+ case CIL_LIST: {
+ struct cil_list *sub_list;
+ cil_copy_expr(db, curr->data, &sub_list);
+ cil_list_append(*new, CIL_LIST, sub_list);
+ break;
+ }
+ case CIL_STRING:
+ cil_list_append(*new, CIL_STRING, curr->data);
+ break;
+ case CIL_DATUM:
+ cil_list_append(*new, curr->flavor, curr->data);
+ break;
+ case CIL_OP:
+ cil_list_append(*new, curr->flavor, curr->data);
+ break;
+ case CIL_CONS_OPERAND:
+ cil_list_append(*new, curr->flavor, curr->data);
+ break;
+ default:
+ cil_log(CIL_INFO, "Unknown flavor %d in expression being copied\n",curr->flavor);
+ cil_list_append(*new, curr->flavor, curr->data);
+ break;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_copy_constrain(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_constrain *orig = data;
+ struct cil_constrain *new = NULL;
+
+ cil_constrain_init(&new);
+ cil_copy_classperms_list(orig->classperms, &new->classperms);
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_validatetrans(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_validatetrans *orig = data;
+ struct cil_validatetrans *new = NULL;
+
+ cil_validatetrans_init(&new);
+
+ new->class_str = orig->class_str;
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_call(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_call *orig = data;
+ struct cil_call *new = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_call_init(&new);
+
+ new->macro_str = orig->macro_str;
+ new->macro = orig->macro;
+
+ if (orig->args_tree != NULL) {
+ cil_tree_init(&new->args_tree);
+ rc = cil_copy_ast(db, orig->args_tree->root, new->args_tree->root);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ new->copied = orig->copied;
+
+ *copy = new;
+
+ return SEPOL_OK;
+
+exit:
+ cil_destroy_call(new);
+ return rc;
+}
+
+int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_macro *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_macro *new;
+ cil_macro_init(&new);
+ if (orig->params != NULL) {
+ cil_copy_list(orig->params, &new->params);
+ }
+
+ *copy = new;
+
+ } else {
+ struct cil_list_item *curr_orig = NULL;
+ struct cil_list_item *curr_new = NULL;
+ struct cil_param *param_orig = NULL;
+ struct cil_param *param_new = NULL;
+
+ if (((struct cil_macro*)datum)->params != NULL) {
+ curr_new = ((struct cil_macro*)datum)->params->head;
+ }
+
+ if (orig->params != NULL) {
+ curr_orig = orig->params->head;
+ }
+
+ if (curr_orig != NULL && curr_new != NULL) {
+ while (curr_orig != NULL) {
+ if (curr_new == NULL) {
+ goto exit;
+ }
+
+ param_orig = (struct cil_param*)curr_orig->data;
+ param_new = (struct cil_param*)curr_new->data;
+ if (param_orig->str != param_new->str) {
+ goto exit;
+ } else if (param_orig->flavor != param_new->flavor) {
+ goto exit;
+ }
+
+ curr_orig = curr_orig->next;
+ curr_new = curr_new->next;
+ }
+
+ if (curr_new != NULL) {
+ goto exit;
+ }
+ } else if (!(curr_orig == NULL && curr_new == NULL)) {
+ goto exit;
+ }
+
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_INFO, "cil_copy_macro: macro cannot be redefined\n");
+ return SEPOL_ERR;
+}
+
+int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_optional *orig = data;
+ char *key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum == NULL) {
+ struct cil_optional *new;
+ cil_optional_init(&new);
+ *copy = new;
+ } else {
+ *copy = datum;
+ }
+
+ return SEPOL_OK;
+}
+
+void cil_copy_fill_ipaddr(struct cil_ipaddr *data, struct cil_ipaddr *new)
+{
+ new->family = data->family;
+ memcpy(&new->ip, &data->ip, sizeof(data->ip));
+}
+
+int cil_copy_ipaddr(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
+{
+ struct cil_ipaddr *orig = data;
+ struct cil_ipaddr *new = NULL;
+ char * key = orig->datum.name;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ cil_log(CIL_INFO, "cil_copy_ipaddr: ipaddress cannot be redefined\n");
+ return SEPOL_ERR;
+ }
+
+ cil_ipaddr_init(&new);
+ cil_copy_fill_ipaddr(orig, new);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_condblock(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_condblock *orig = data;
+ struct cil_condblock *new = *copy;
+ cil_condblock_init(&new);
+ new->flavor = orig->flavor;
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_boolif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_booleanif *orig = data;
+ struct cil_booleanif *new = NULL;
+
+ cil_boolif_init(&new);
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+ new->preserved_tunable = orig->preserved_tunable;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_tunif(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_tunableif *orig = data;
+ struct cil_tunableif *new = NULL;
+
+ cil_tunif_init(&new);
+
+ cil_copy_expr(db, orig->str_expr, &new->str_expr);
+ cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_default(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_default *orig = data;
+ struct cil_default *new = NULL;
+
+ cil_default_init(&new);
+
+ new->flavor = orig->flavor;
+
+ if (orig->class_strs != NULL) {
+ cil_copy_list(orig->class_strs, &new->class_strs);
+ }
+
+ new->object = orig->object;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_defaultrange(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_defaultrange *orig = data;
+ struct cil_defaultrange *new = NULL;
+
+ cil_defaultrange_init(&new);
+
+ if (orig->class_strs != NULL) {
+ cil_copy_list(orig->class_strs, &new->class_strs);
+ }
+
+ new->object_range = orig->object_range;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_handleunknown(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_handleunknown *orig = data;
+ struct cil_handleunknown *new = NULL;
+
+ cil_handleunknown_init(&new);
+ new->handle_unknown = orig->handle_unknown;
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_mls(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_mls *orig = data;
+ struct cil_mls *new = NULL;
+
+ cil_mls_init(&new);
+ new->value = orig->value;
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_bounds *orig = data;
+ struct cil_bounds *new = NULL;
+
+ cil_bounds_init(&new);
+
+ new->parent_str = orig->parent_str;
+ new->child_str = orig->child_str;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+ struct cil_src_info *orig = data;
+ struct cil_src_info *new = NULL;
+
+ cil_src_info_init(&new);
+
+ new->is_cil = orig->is_cil;
+ new->path = orig->path;
+
+ *copy = new;
+
+ return SEPOL_OK;
+}
+
+int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *parent = NULL;
+ struct cil_tree_node *new = NULL;
+ struct cil_db *db = NULL;
+ struct cil_args_copy *args = NULL;
+ struct cil_tree_node *namespace = NULL;
+ struct cil_param *param = NULL;
+ enum cil_sym_index sym_index = CIL_SYM_UNKNOWN;
+ symtab_t *symtab = NULL;
+ void *data = NULL;
+ int (*copy_func)(struct cil_db *db, void *data, void **copy, symtab_t *symtab) = NULL;
+ struct cil_blockinherit *blockinherit = NULL;
+
+ if (orig == NULL || extra_args == NULL) {
+ goto exit;
+ }
+
+ args = extra_args;
+ parent = args->dest;
+ db = args->db;
+
+
+ switch (orig->flavor) {
+ case CIL_BLOCK:
+ copy_func = &cil_copy_block;
+ break;
+ case CIL_BLOCKABSTRACT:
+ copy_func = &cil_copy_blockabstract;
+ break;
+ case CIL_BLOCKINHERIT:
+ copy_func = &cil_copy_blockinherit;
+ break;
+ case CIL_POLICYCAP:
+ copy_func = &cil_copy_policycap;
+ break;
+ case CIL_PERM:
+ case CIL_MAP_PERM:
+ copy_func = &cil_copy_perm;
+ break;
+ case CIL_CLASSMAPPING:
+ copy_func = &cil_copy_classmapping;
+ break;
+ case CIL_CLASS:
+ case CIL_COMMON:
+ case CIL_MAP_CLASS:
+ copy_func = &cil_copy_class;
+ break;
+ case CIL_CLASSORDER:
+ copy_func = &cil_copy_classorder;
+ break;
+ case CIL_CLASSPERMISSION:
+ copy_func = &cil_copy_classpermission;
+ break;
+ case CIL_CLASSPERMISSIONSET:
+ copy_func = &cil_copy_classpermissionset;
+ break;
+ case CIL_CLASSCOMMON:
+ copy_func = &cil_copy_classcommon;
+ break;
+ case CIL_SID:
+ copy_func = &cil_copy_sid;
+ break;
+ case CIL_SIDCONTEXT:
+ copy_func = &cil_copy_sidcontext;
+ break;
+ case CIL_SIDORDER:
+ copy_func = &cil_copy_sidorder;
+ break;
+ case CIL_USER:
+ copy_func = &cil_copy_user;
+ break;
+ case CIL_USERATTRIBUTE:
+ copy_func = &cil_copy_userattribute;
+ break;
+ case CIL_USERATTRIBUTESET:
+ copy_func = &cil_copy_userattributeset;
+ break;
+ case CIL_USERROLE:
+ copy_func = &cil_copy_userrole;
+ break;
+ case CIL_USERLEVEL:
+ copy_func = &cil_copy_userlevel;
+ break;
+ case CIL_USERRANGE:
+ copy_func = &cil_copy_userrange;
+ break;
+ case CIL_USERBOUNDS:
+ copy_func = &cil_copy_bounds;
+ break;
+ case CIL_USERPREFIX:
+ copy_func = &cil_copy_userprefix;
+ break;
+ case CIL_ROLE:
+ copy_func = &cil_copy_role;
+ break;
+ case CIL_ROLETYPE:
+ copy_func = &cil_copy_roletype;
+ break;
+ case CIL_ROLEBOUNDS:
+ copy_func = &cil_copy_bounds;
+ break;
+ case CIL_ROLEATTRIBUTE:
+ copy_func = &cil_copy_roleattribute;
+ break;
+ case CIL_ROLEATTRIBUTESET:
+ copy_func = &cil_copy_roleattributeset;
+ break;
+ case CIL_ROLEALLOW:
+ copy_func = &cil_copy_roleallow;
+ break;
+ case CIL_TYPE:
+ copy_func = &cil_copy_type;
+ break;
+ case CIL_TYPEBOUNDS:
+ copy_func = &cil_copy_bounds;
+ break;
+ case CIL_TYPEPERMISSIVE:
+ copy_func = cil_copy_typepermissive;
+ break;
+ case CIL_TYPEATTRIBUTE:
+ copy_func = &cil_copy_typeattribute;
+ break;
+ case CIL_TYPEATTRIBUTESET:
+ copy_func = &cil_copy_typeattributeset;
+ break;
+ case CIL_TYPEALIAS:
+ copy_func = &cil_copy_alias;
+ break;
+ case CIL_TYPEALIASACTUAL:
+ copy_func = &cil_copy_aliasactual;
+ break;
+ case CIL_ROLETRANSITION:
+ copy_func = &cil_copy_roletransition;
+ break;
+ case CIL_NAMETYPETRANSITION:
+ copy_func = &cil_copy_nametypetransition;
+ break;
+ case CIL_RANGETRANSITION:
+ copy_func = &cil_copy_rangetransition;
+ break;
+ case CIL_TUNABLE:
+ copy_func = &cil_copy_tunable;
+ break;
+ case CIL_BOOL:
+ copy_func = &cil_copy_bool;
+ break;
+ case CIL_AVRULE:
+ case CIL_AVRULEX:
+ copy_func = &cil_copy_avrule;
+ break;
+ case CIL_PERMISSIONX:
+ copy_func = &cil_copy_permissionx;
+ break;
+ case CIL_TYPE_RULE:
+ copy_func = &cil_copy_type_rule;
+ break;
+ case CIL_SENS:
+ copy_func = &cil_copy_sens;
+ break;
+ case CIL_SENSALIAS:
+ copy_func = &cil_copy_alias;
+ break;
+ case CIL_SENSALIASACTUAL:
+ copy_func = &cil_copy_aliasactual;
+ break;
+ case CIL_CAT:
+ copy_func = &cil_copy_cat;
+ break;
+ case CIL_CATALIAS:
+ copy_func = &cil_copy_alias;
+ break;
+ case CIL_CATALIASACTUAL:
+ copy_func = &cil_copy_aliasactual;
+ break;
+ case CIL_CATSET:
+ copy_func = &cil_copy_catset;
+ break;
+ case CIL_SENSCAT:
+ copy_func = &cil_copy_senscat;
+ break;
+ case CIL_CATORDER:
+ copy_func = &cil_copy_catorder;
+ break;
+ case CIL_SENSITIVITYORDER:
+ copy_func = &cil_copy_sensitivityorder;
+ break;
+ case CIL_LEVEL:
+ copy_func = &cil_copy_level;
+ break;
+ case CIL_LEVELRANGE:
+ copy_func = &cil_copy_levelrange;
+ break;
+ case CIL_CONTEXT:
+ copy_func = &cil_copy_context;
+ break;
+ case CIL_NETIFCON:
+ copy_func = &cil_copy_netifcon;
+ break;
+ case CIL_GENFSCON:
+ copy_func = &cil_copy_genfscon;
+ break;
+ case CIL_FILECON:
+ copy_func = &cil_copy_filecon;
+ break;
+ case CIL_NODECON:
+ copy_func = &cil_copy_nodecon;
+ break;
+ case CIL_PORTCON:
+ copy_func = &cil_copy_portcon;
+ break;
+ case CIL_PIRQCON:
+ copy_func = &cil_copy_pirqcon;
+ break;
+ case CIL_IOMEMCON:
+ copy_func = &cil_copy_iomemcon;
+ break;
+ case CIL_IOPORTCON:
+ copy_func = &cil_copy_ioportcon;
+ break;
+ case CIL_PCIDEVICECON:
+ copy_func = &cil_copy_pcidevicecon;
+ break;
+ case CIL_DEVICETREECON:
+ copy_func = &cil_copy_devicetreecon;
+ break;
+ case CIL_FSUSE:
+ copy_func = &cil_copy_fsuse;
+ break;
+ case CIL_CONSTRAIN:
+ case CIL_MLSCONSTRAIN:
+ copy_func = &cil_copy_constrain;
+ break;
+ case CIL_VALIDATETRANS:
+ case CIL_MLSVALIDATETRANS:
+ copy_func = &cil_copy_validatetrans;
+ break;
+ case CIL_CALL:
+ copy_func = &cil_copy_call;
+ break;
+ case CIL_MACRO:
+ copy_func = &cil_copy_macro;
+ break;
+ case CIL_NODE:
+ copy_func = &cil_copy_node;
+ break;
+ case CIL_OPTIONAL:
+ copy_func = &cil_copy_optional;
+ break;
+ case CIL_IPADDR:
+ copy_func = &cil_copy_ipaddr;
+ break;
+ case CIL_CONDBLOCK:
+ copy_func = &cil_copy_condblock;
+ break;
+ case CIL_BOOLEANIF:
+ copy_func = &cil_copy_boolif;
+ break;
+ case CIL_TUNABLEIF:
+ copy_func = &cil_copy_tunif;
+ break;
+ case CIL_DEFAULTUSER:
+ case CIL_DEFAULTROLE:
+ case CIL_DEFAULTTYPE:
+ copy_func = &cil_copy_default;
+ break;
+ case CIL_DEFAULTRANGE:
+ copy_func = &cil_copy_defaultrange;
+ break;
+ case CIL_HANDLEUNKNOWN:
+ copy_func = &cil_copy_handleunknown;
+ break;
+ case CIL_MLS:
+ copy_func = &cil_copy_mls;
+ break;
+ case CIL_SRC_INFO:
+ copy_func = &cil_copy_src_info;
+ break;
+ default:
+ goto exit;
+ }
+
+ if (orig->flavor >= CIL_MIN_DECLARATIVE) {
+ rc = cil_flavor_to_symtab_index(orig->flavor, &sym_index);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_get_symtab(parent, &symtab, sym_index);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = (*copy_func)(db, orig->data, &data, symtab);
+ if (rc == SEPOL_OK) {
+ cil_tree_node_init(&new);
+
+ new->parent = parent;
+ new->line = orig->line;
+ new->hll_line = orig->hll_line;
+ new->flavor = orig->flavor;
+ new->data = data;
+
+ if (orig->flavor >= CIL_MIN_DECLARATIVE) {
+ rc = cil_symtab_insert(symtab, ((struct cil_symtab_datum*)orig->data)->name, ((struct cil_symtab_datum*)data), new);
+
+ namespace = new;
+ while (namespace->flavor != CIL_MACRO && namespace->flavor != CIL_BLOCK && namespace->flavor != CIL_ROOT) {
+ namespace = namespace->parent;
+ }
+
+ if (namespace->flavor == CIL_MACRO) {
+ struct cil_macro *macro = namespace->data;
+ struct cil_list *param_list = macro->params;
+ if (param_list != NULL) {
+ struct cil_list_item *item;
+ cil_list_for_each(item, param_list) {
+ param = item->data;
+ if (param->flavor == new->flavor) {
+ if (param->str == ((struct cil_symtab_datum*)new->data)->name) {
+ cil_tree_log(orig, CIL_ERR, "%s %s shadows a macro parameter", cil_node_to_string(new), ((struct cil_symtab_datum*)orig->data)->name);
+ cil_tree_log(namespace, CIL_ERR, "Note: macro declaration");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (new->flavor == CIL_BLOCKINHERIT) {
+ blockinherit = new->data;
+ // if a blockinherit statement is copied before blockinherit are
+ // resolved (like in an in-statement), the block will not have been
+ // resolved yet, so there's nothing to append yet. This is fine,
+ // the copied blockinherit statement will be handled later, as if
+ // it wasn't in an in-statement
+ if (blockinherit->block != NULL) {
+ cil_list_append(blockinherit->block->bi_nodes, CIL_NODE, new);
+ }
+ }
+
+ if (parent->cl_head == NULL) {
+ parent->cl_head = new;
+ parent->cl_tail = new;
+ } else {
+ parent->cl_tail->next = new;
+ parent->cl_tail = new;
+ }
+
+ if (orig->cl_head != NULL) {
+ args->dest = new;
+ }
+ } else {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_node_destroy(&new);
+ return rc;
+}
+
+int __cil_copy_last_child_helper(__attribute__((unused)) struct cil_tree_node *orig, void *extra_args)
+{
+ struct cil_tree_node *node = NULL;
+ struct cil_args_copy *args = NULL;
+
+ args = extra_args;
+ node = args->dest;
+
+ if (node->flavor != CIL_ROOT) {
+ args->dest = node->parent;
+ }
+
+ return SEPOL_OK;
+}
+
+// dest is the parent node to copy into
+// if the copy is for a call to a macro, dest should be a pointer to the call
+int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_node *dest)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_copy extra_args;
+
+ extra_args.dest = dest;
+ extra_args.db = db;
+
+ rc = cil_tree_walk(orig, __cil_copy_node_helper, NULL, __cil_copy_last_child_helper, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "cil_tree_walk failed, rc: %d\n", rc);
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
diff --git a/libsepol/cil/src/cil_copy_ast.h b/libsepol/cil/src/cil_copy_ast.h
new file mode 100644
index 0000000..78c34b8
--- /dev/null
+++ b/libsepol/cil/src/cil_copy_ast.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_COPY_H_
+#define CIL_COPY_H_
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+
+void cil_copy_list(struct cil_list *orig, struct cil_list **copy);
+int cil_copy_expr(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
+
+int cil_copy_block(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_blockabstract(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_blockinherit(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_perm(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_class(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classmapping(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_permset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+
+void cil_copy_classperms(struct cil_classperms *orig, struct cil_classperms **new);
+void cil_copy_classperms_set(struct cil_classperms_set *orig, struct cil_classperms_set **new);
+void cil_copy_classperms_list(struct cil_list *orig, struct cil_list **new);
+int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab);
+int cil_copy_common(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_classcommon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sid(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sidorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_user(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userrole(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userbounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_userprefix(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_role(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roletype(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_rolebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_roleallow(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_type(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typepermissive(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typeattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_typealias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_nametypetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_rangetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_bool(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_avrule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_type_rule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sens(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sensalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_cat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_senscat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_catorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_sensitivityorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_level(struct cil_db *db, struct cil_level *orig, struct cil_level **new);
+int cil_copy_level(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_levelrange(struct cil_db *db, struct cil_levelrange *orig, struct cil_levelrange *new);
+int cil_copy_levelrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_context(struct cil_db *db, struct cil_context *orig, struct cil_context *new);
+int cil_copy_context(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_filecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_portcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_ioportcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_fsuse(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_exrp(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
+int cil_copy_constrain(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_validatetrans(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_call(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_optional(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+void cil_copy_fill_ipaddr(struct cil_ipaddr *orig, struct cil_ipaddr *new);
+int cil_copy_ipaddr(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_boolif(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+
+int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_node *dest);
+
+#endif
diff --git a/libsepol/cil/src/cil_find.c b/libsepol/cil/src/cil_find.c
new file mode 100644
index 0000000..4134242
--- /dev/null
+++ b/libsepol/cil/src/cil_find.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/ebitmap.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_list.h"
+#include "cil_log.h"
+#include "cil_symtab.h"
+
+struct cil_args_find {
+ enum cil_flavor flavor;
+ void *target;
+ struct cil_list *matching;
+ int match_self;
+};
+
+static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
+{
+ enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
+ enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
+
+ if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+ struct cil_type *t1 = (struct cil_type *)d1;
+ struct cil_type *t2 = (struct cil_type *)d2;
+ if (t1->value == t2->value) {
+ return CIL_TRUE;
+ }
+ } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+ struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
+ struct cil_type *t = (struct cil_type *)d2;
+ if (ebitmap_get_bit(a->types, t->value)) {
+ return CIL_TRUE;
+ }
+ } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
+ struct cil_type *t = (struct cil_type *)d1;
+ struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
+ if (ebitmap_get_bit(a->types, t->value)) {
+ return CIL_TRUE;
+ }
+ } else {
+ /* Both are attributes */
+ struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
+ struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
+ if (d1 == d2) {
+ return CIL_TRUE;
+ } else if (ebitmap_match_any(a1->types, a2->types)) {
+ return CIL_TRUE;
+ }
+ }
+ return CIL_FALSE;
+}
+
+static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
+{
+ int rc = SEPOL_OK;
+ enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
+ enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
+
+ if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+ struct cil_type *t1 = (struct cil_type *)d1;
+ struct cil_type *t2 = (struct cil_type *)d2;
+ if (t1->value == t2->value) {
+ ebitmap_set_bit(matches, t1->value, 1);
+ }
+ } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
+ struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
+ struct cil_type *t = (struct cil_type *)d2;
+ if (ebitmap_get_bit(a->types, t->value)) {
+ ebitmap_set_bit(matches, t->value, 1);
+ }
+ } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
+ struct cil_type *t = (struct cil_type *)d1;
+ struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
+ if (ebitmap_get_bit(a->types, t->value)) {
+ ebitmap_set_bit(matches, t->value, 1);
+ }
+ } else {
+ /* Both are attributes */
+ struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
+ struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
+ rc = ebitmap_and(matches, a1->types, a2->types);
+ }
+
+ return rc;
+}
+
+/* s1 is the src type that is matched with a self
+ * s2, and t2 are the source and type of the other rule
+ */
+static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2)
+{
+ int rc;
+ struct cil_tree_node *n1 = s1->nodes->head->data;
+ if (n1->flavor != CIL_TYPEATTRIBUTE) {
+ rc = cil_type_match_any(s1, t2);
+ } else {
+ struct cil_typeattribute *a = (struct cil_typeattribute *)s1;
+ ebitmap_t map;
+ ebitmap_init(&map);
+ rc = cil_type_matches(&map, s2, t2);
+ if (rc < 0) {
+ ebitmap_destroy(&map);
+ goto exit;
+ }
+ if (map.node == NULL) {
+ rc = CIL_FALSE;
+ goto exit;
+ }
+ rc = ebitmap_match_any(&map, a->types);
+ ebitmap_destroy(&map);
+ }
+
+exit:
+ return rc;
+}
+
+static int cil_classperms_match_any(struct cil_classperms *cp1, struct cil_classperms *cp2)
+{
+ struct cil_class *c1 = cp1->class;
+ struct cil_class *c2 = cp2->class;
+ struct cil_list_item *i1, *i2;
+
+ if (&c1->datum != &c2->datum) return CIL_FALSE;
+
+ cil_list_for_each(i1, cp1->perms) {
+ struct cil_perm *p1 = i1->data;
+ cil_list_for_each(i2, cp2->perms) {
+ struct cil_perm *p2 = i2->data;
+ if (&p1->datum == &p2->datum) return CIL_TRUE;
+ }
+ }
+ return CIL_FALSE;
+}
+
+static int __cil_classperms_list_match_any(struct cil_classperms *cp1, struct cil_list *cpl2)
+{
+ int rc;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, cpl2) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ rc = cil_classperms_match_any(cp1, cp);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ rc = __cil_classperms_list_match_any(cp1, cmp->classperms);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = __cil_classperms_list_match_any(cp1, cp->classperms);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ }
+ }
+ return CIL_FALSE;
+}
+
+static int cil_classperms_list_match_any(struct cil_list *cpl1, struct cil_list *cpl2)
+{
+ int rc;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, cpl1) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ rc = __cil_classperms_list_match_any(cp, cpl2);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ rc = cil_classperms_list_match_any(cmp->classperms, cpl2);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = cil_classperms_list_match_any(cp->classperms, cpl2);
+ if (rc == CIL_TRUE) return CIL_TRUE;
+ }
+ }
+ return CIL_FALSE;
+}
+
+static void __add_classes_from_classperms_list(struct cil_list *classperms, struct cil_list *class_list)
+{
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ cil_list_append(class_list, CIL_CLASS, cp->class);
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ __add_classes_from_classperms_list(cmp->classperms, class_list);
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ __add_classes_from_classperms_list(cp->classperms, class_list);
+ }
+ }
+}
+
+static int __add_classes_from_map_perms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct cil_list *class_list = args;
+ struct cil_perm *cmp = (struct cil_perm *)d;
+
+ __add_classes_from_classperms_list(cmp->classperms, class_list);
+
+ return SEPOL_OK;
+}
+
+struct cil_list *cil_expand_class(struct cil_class *class)
+{
+ struct cil_list *class_list;
+
+ cil_list_init(&class_list, CIL_CLASS);
+
+ if (FLAVOR(class) == CIL_CLASS) {
+ cil_list_append(class_list, CIL_CLASS, class);
+ } else { /* MAP */
+ cil_symtab_map(&class->perms, __add_classes_from_map_perms, class_list);
+ }
+
+ return class_list;
+}
+
+static int cil_permissionx_match_any(struct cil_permissionx *px1, struct cil_permissionx *px2)
+{
+ int rc = CIL_FALSE;
+ struct cil_list *cl1 = NULL;
+ struct cil_list *cl2 = NULL;
+
+ if (px1->kind != px2->kind) goto exit;
+
+ if (!ebitmap_match_any(px1->perms, px2->perms)) goto exit;
+
+ cl1 = cil_expand_class(px1->obj);
+ cl2 = cil_expand_class(px2->obj);
+
+ if (!cil_list_match_any(cl1, cl2)) goto exit;
+
+ rc = CIL_TRUE;
+
+exit:
+ cil_list_destroy(&cl1, CIL_FALSE);
+ cil_list_destroy(&cl2, CIL_FALSE);
+
+ return rc;
+}
+
+int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self)
+{
+ int rc = SEPOL_OK;
+ struct cil_symtab_datum *s1 = avrule->src;
+ struct cil_symtab_datum *t1 = avrule->tgt;
+ struct cil_symtab_datum *s2 = target->src;
+ struct cil_symtab_datum *t2 = target->tgt;
+
+ if (match_self != CIL_TRUE && avrule == target) goto exit;
+
+ if (avrule->rule_kind != target->rule_kind) goto exit;
+
+ if (avrule->is_extended != target->is_extended) goto exit;
+
+ if (!cil_type_match_any(s1, s2)) goto exit;
+
+ if (t1->fqn != CIL_KEY_SELF && t2->fqn != CIL_KEY_SELF) {
+ if (!cil_type_match_any(t1, t2)) goto exit;
+ } else {
+ if (t1->fqn == CIL_KEY_SELF && t2->fqn == CIL_KEY_SELF) {
+ /* The earlier check whether s1 and s2 matches is all that is needed */
+ } else if (t1->fqn == CIL_KEY_SELF) {
+ rc = cil_self_match_any(s1, s2, t2);
+ if (rc < 0) {
+ goto exit;
+ } else if (rc == CIL_FALSE) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ } else if (t2->fqn == CIL_KEY_SELF) {
+ rc = cil_self_match_any(s2, s1, t1);
+ if (rc < 0) {
+ goto exit;
+ } else if (rc == CIL_FALSE) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ }
+ }
+
+ if (!target->is_extended) {
+ if (cil_classperms_list_match_any(avrule->perms.classperms, target->perms.classperms)) {
+ cil_list_append(matching, CIL_NODE, node);
+ }
+ } else {
+ if (cil_permissionx_match_any(avrule->perms.x.permx, target->perms.x.permx)) {
+ cil_list_append(matching, CIL_NODE, node);
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_find_matching_avrule_in_ast(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_OK;
+ struct cil_args_find *args = extra_args;
+
+ if (node->flavor == CIL_BLOCK) {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ goto exit;
+ }
+ } else if (node->flavor == CIL_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ goto exit;
+ } else if (node->flavor == CIL_AVRULE || node->flavor == CIL_AVRULEX) {
+ if (node->flavor == args->flavor) {
+ rc = cil_find_matching_avrule(node, node->data, args->target, args->matching, args->match_self);
+ }
+ }
+
+exit:
+ return rc;
+}
+
+int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self)
+{
+ int rc;
+ struct cil_args_find args;
+
+ args.flavor = flavor;
+ args.target = target;
+ args.matching = matching;
+ args.match_self = match_self;
+
+ rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args);
+ if (rc) {
+ cil_log(CIL_ERR, "An error occurred while searching for avrule in AST\n");
+ }
+
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_find.h b/libsepol/cil/src/cil_find.h
new file mode 100644
index 0000000..463ef34
--- /dev/null
+++ b/libsepol/cil/src/cil_find.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+#ifndef CIL_FIND_H_
+#define CIL_FIND_H_
+
+int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self);
+struct cil_list *cil_expand_class(struct cil_class *class);
+
+#endif
diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
new file mode 100644
index 0000000..cd08b97
--- /dev/null
+++ b/libsepol/cil/src/cil_flavor.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2013 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_FLAVOR_H_
+#define CIL_FLAVOR_H_
+
+/*
+ Tree/list node types
+*/
+#define CIL_MIN_OP_OPERANDS 1000
+#define CIL_MIN_DECLARATIVE 2000
+
+enum cil_flavor {
+ CIL_NONE = 0,
+ CIL_ROOT,
+ CIL_NODE,
+ CIL_STRING,
+ CIL_DATUM,
+ CIL_LIST,
+ CIL_LIST_ITEM,
+ CIL_PARAM,
+ CIL_ARGS,
+ CIL_BLOCKINHERIT,
+ CIL_BLOCKABSTRACT,
+ CIL_IN,
+ CIL_CALL,
+ CIL_BOOLEANIF,
+ CIL_TUNABLEIF,
+ CIL_CONDBLOCK,
+ CIL_CONDTRUE,
+ CIL_CONDFALSE,
+ CIL_CLASSORDER,
+ CIL_CLASSCOMMON,
+ CIL_CLASSMAPPING,
+ CIL_CLASSPERMS,
+ CIL_CLASSPERMS_SET,
+ CIL_CLASSPERMISSIONSET,
+ CIL_USERPREFIX,
+ CIL_USERROLE,
+ CIL_USERATTRIBUTESET,
+ CIL_USERLEVEL,
+ CIL_USERRANGE,
+ CIL_USERBOUNDS,
+ CIL_SELINUXUSER,
+ CIL_SELINUXUSERDEFAULT,
+ CIL_ROLEATTRIBUTESET,
+ CIL_ROLETYPE,
+ CIL_ROLEBOUNDS,
+ CIL_TYPEATTRIBUTESET,
+ CIL_TYPEALIASACTUAL,
+ CIL_TYPEBOUNDS,
+ CIL_TYPEPERMISSIVE,
+ CIL_SENSALIASACTUAL,
+ CIL_SENSITIVITYORDER,
+ CIL_SENSCAT,
+ CIL_CATALIASACTUAL,
+ CIL_CATORDER,
+ CIL_SIDORDER,
+ CIL_ROLEALLOW,
+ CIL_AVRULE,
+ CIL_AVRULEX,
+ CIL_ROLETRANSITION,
+ CIL_TYPE_RULE,
+ CIL_NAMETYPETRANSITION,
+ CIL_RANGETRANSITION,
+ CIL_CONSTRAIN,
+ CIL_MLSCONSTRAIN,
+ CIL_VALIDATETRANS,
+ CIL_MLSVALIDATETRANS,
+ CIL_SIDCONTEXT,
+ CIL_FSUSE,
+ CIL_FILECON,
+ CIL_PORTCON,
+ CIL_NODECON,
+ CIL_GENFSCON,
+ CIL_NETIFCON,
+ CIL_PIRQCON,
+ CIL_IOMEMCON,
+ CIL_IOPORTCON,
+ CIL_PCIDEVICECON,
+ CIL_DEVICETREECON,
+ CIL_DEFAULTUSER,
+ CIL_DEFAULTROLE,
+ CIL_DEFAULTTYPE,
+ CIL_DEFAULTRANGE,
+ CIL_HANDLEUNKNOWN,
+ CIL_MLS,
+ CIL_SRC_INFO,
+
+/*
+ * boolean constraint set catset
+ * dom X
+ * domby X
+ * incomp X
+ * eq X X
+ * ne X X
+ * and X X X X
+ * not X X X X
+ * or X X X X
+ * xor X X X
+ * all X X
+ * range X
+*/
+ CIL_OP = CIL_MIN_OP_OPERANDS,
+ CIL_ALL,
+ CIL_AND,
+ CIL_OR,
+ CIL_XOR,
+ CIL_NOT,
+ CIL_EQ,
+ CIL_NEQ,
+ CIL_RANGE,
+ CIL_CONS_DOM,
+ CIL_CONS_DOMBY,
+ CIL_CONS_INCOMP,
+ CIL_CONS_OPERAND,
+ CIL_CONS_U1,
+ CIL_CONS_U2,
+ CIL_CONS_U3,
+ CIL_CONS_T1,
+ CIL_CONS_T2,
+ CIL_CONS_T3,
+ CIL_CONS_R1,
+ CIL_CONS_R2,
+ CIL_CONS_R3,
+ CIL_CONS_L1,
+ CIL_CONS_L2,
+ CIL_CONS_H1,
+ CIL_CONS_H2,
+
+ CIL_BLOCK = CIL_MIN_DECLARATIVE,
+ CIL_MACRO,
+ CIL_OPTIONAL,
+ CIL_BOOL,
+ CIL_TUNABLE,
+ CIL_PERM,
+ CIL_MAP_PERM,
+ CIL_COMMON,
+ CIL_CLASS,
+ CIL_MAP_CLASS,
+ CIL_CLASSPERMISSION,
+ CIL_USER,
+ CIL_USERATTRIBUTE,
+ CIL_ROLE,
+ CIL_ROLEATTRIBUTE,
+ CIL_TYPE,
+ CIL_TYPEATTRIBUTE,
+ CIL_TYPEALIAS,
+ CIL_SENS,
+ CIL_SENSALIAS,
+ CIL_CAT,
+ CIL_CATSET,
+ CIL_CATALIAS,
+ CIL_LEVEL,
+ CIL_LEVELRANGE,
+ CIL_SID,
+ CIL_NAME,
+ CIL_CONTEXT,
+ CIL_IPADDR,
+ CIL_POLICYCAP,
+ CIL_PERMISSIONX
+};
+
+
+#endif /* CIL_FLAVOR_H_ */
diff --git a/libsepol/cil/src/cil_fqn.c b/libsepol/cil/src/cil_fqn.c
new file mode 100644
index 0000000..dad1347
--- /dev/null
+++ b/libsepol/cil/src/cil_fqn.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_strpool.h"
+#include "cil_symtab.h"
+
+struct cil_fqn_args {
+ char prefix[CIL_MAX_NAME_LENGTH];
+ int len;
+ struct cil_tree_node *node;
+};
+
+static int __cil_fqn_qualify_decls(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct cil_fqn_args *fqn_args = args;
+ struct cil_symtab_datum *datum = (struct cil_symtab_datum *)d;
+ int newlen;
+ char prefix[CIL_MAX_NAME_LENGTH];
+ int rc = SEPOL_OK;
+
+ if (fqn_args->len == 0) {
+ goto exit;
+ }
+
+ newlen = fqn_args->len + strlen(datum->name);
+ if (newlen >= CIL_MAX_NAME_LENGTH) {
+ cil_log(CIL_INFO, "Fully qualified name for %s is too long\n", datum->name);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ strcpy(prefix, fqn_args->prefix);
+ strcat(prefix, datum->name);
+ datum->fqn = cil_strpool_add(prefix);
+
+exit:
+ return rc;
+}
+
+static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct cil_fqn_args *fqn_args = args;
+ struct cil_fqn_args child_args;
+ struct cil_block *block = (struct cil_block *)d;
+ struct cil_symtab_datum *datum = (struct cil_symtab_datum *)block;
+ struct cil_tree_node *node = NODE(datum);
+ int i;
+ int rc = SEPOL_OK;
+
+ if (node->flavor != CIL_BLOCK) {
+ goto exit;
+ }
+
+ int newlen = fqn_args->len + strlen(datum->name) + 1;
+ if (newlen >= CIL_MAX_NAME_LENGTH) {
+ cil_log(CIL_INFO, "Fully qualified name for block %s is too long\n", datum->name);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ child_args.node = node;
+ child_args.len = newlen;
+ strcpy(child_args.prefix, fqn_args->prefix);
+ strcat(child_args.prefix, datum->name);
+ strcat(child_args.prefix, ".");
+
+ for (i=1; i<CIL_SYM_NUM; i++) {
+ switch (i) {
+ case CIL_SYM_CLASSPERMSETS:
+ case CIL_SYM_CONTEXTS:
+ case CIL_SYM_LEVELRANGES:
+ case CIL_SYM_IPADDRS:
+ case CIL_SYM_NAMES:
+ case CIL_SYM_PERMX:
+ /* These do not show up in the kernal policy */
+ break;
+ case CIL_SYM_POLICYCAPS:
+ /* Valid policy capability names are defined in libsepol */
+ break;
+ default:
+ rc = cil_symtab_map(&(block->symtab[i]), __cil_fqn_qualify_decls, &child_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ }
+
+ rc = cil_symtab_map(&(block->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &child_args);
+
+exit:
+ if (rc != SEPOL_OK) {
+ cil_tree_log(child_args.node, CIL_ERR,"Problem qualifying names in block");
+ }
+
+ return rc;
+}
+
+int cil_fqn_qualify(struct cil_tree_node *root_node)
+{
+ struct cil_root *root = root_node->data;
+ struct cil_fqn_args fqn_args;
+
+ fqn_args.prefix[0] = '\0';
+ fqn_args.len = 0;
+ fqn_args.node = root_node;
+
+ return cil_symtab_map(&(root->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &fqn_args);
+}
+
diff --git a/libsepol/cil/src/cil_fqn.h b/libsepol/cil/src/cil_fqn.h
new file mode 100644
index 0000000..9248ca1
--- /dev/null
+++ b/libsepol/cil/src/cil_fqn.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_FQN_H_
+#define CIL_FQN_H_
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+
+int cil_fqn_qualify(struct cil_tree_node *root_node);
+
+#endif /* CIL_FQN_H_ */
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
new file mode 100644
index 0000000..5875dc9
--- /dev/null
+++ b/libsepol/cil/src/cil_internal.h
@@ -0,0 +1,1034 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_INTERNAL_H_
+#define CIL_INTERNAL_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/policydb.h>
+
+#include <cil/cil.h>
+
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+#include "cil_mem.h"
+
+#define CIL_MAX_NAME_LENGTH 2048
+
+
+enum cil_pass {
+ CIL_PASS_INIT = 0,
+
+ CIL_PASS_TIF,
+ CIL_PASS_IN,
+ CIL_PASS_BLKIN_LINK,
+ CIL_PASS_BLKIN_COPY,
+ CIL_PASS_BLKABS,
+ CIL_PASS_MACRO,
+ CIL_PASS_CALL1,
+ CIL_PASS_CALL2,
+ CIL_PASS_ALIAS1,
+ CIL_PASS_ALIAS2,
+ CIL_PASS_MISC1,
+ CIL_PASS_MLS,
+ CIL_PASS_MISC2,
+ CIL_PASS_MISC3,
+
+ CIL_PASS_NUM
+};
+
+
+/*
+ Keywords
+*/
+char *CIL_KEY_CONS_T1;
+char *CIL_KEY_CONS_T2;
+char *CIL_KEY_CONS_T3;
+char *CIL_KEY_CONS_R1;
+char *CIL_KEY_CONS_R2;
+char *CIL_KEY_CONS_R3;
+char *CIL_KEY_CONS_U1;
+char *CIL_KEY_CONS_U2;
+char *CIL_KEY_CONS_U3;
+char *CIL_KEY_CONS_L1;
+char *CIL_KEY_CONS_L2;
+char *CIL_KEY_CONS_H1;
+char *CIL_KEY_CONS_H2;
+char *CIL_KEY_AND;
+char *CIL_KEY_OR;
+char *CIL_KEY_NOT;
+char *CIL_KEY_EQ;
+char *CIL_KEY_NEQ;
+char *CIL_KEY_CONS_DOM;
+char *CIL_KEY_CONS_DOMBY;
+char *CIL_KEY_CONS_INCOMP;
+char *CIL_KEY_CONDTRUE;
+char *CIL_KEY_CONDFALSE;
+char *CIL_KEY_SELF;
+char *CIL_KEY_OBJECT_R;
+char *CIL_KEY_STAR;
+char *CIL_KEY_TCP;
+char *CIL_KEY_UDP;
+char *CIL_KEY_DCCP;
+char *CIL_KEY_AUDITALLOW;
+char *CIL_KEY_TUNABLEIF;
+char *CIL_KEY_ALLOW;
+char *CIL_KEY_DONTAUDIT;
+char *CIL_KEY_TYPETRANSITION;
+char *CIL_KEY_TYPECHANGE;
+char *CIL_KEY_CALL;
+char *CIL_KEY_TUNABLE;
+char *CIL_KEY_XOR;
+char *CIL_KEY_ALL;
+char *CIL_KEY_RANGE;
+char *CIL_KEY_GLOB;
+char *CIL_KEY_FILE;
+char *CIL_KEY_DIR;
+char *CIL_KEY_CHAR;
+char *CIL_KEY_BLOCK;
+char *CIL_KEY_SOCKET;
+char *CIL_KEY_PIPE;
+char *CIL_KEY_SYMLINK;
+char *CIL_KEY_ANY;
+char *CIL_KEY_XATTR;
+char *CIL_KEY_TASK;
+char *CIL_KEY_TRANS;
+char *CIL_KEY_TYPE;
+char *CIL_KEY_ROLE;
+char *CIL_KEY_USER;
+char *CIL_KEY_USERATTRIBUTE;
+char *CIL_KEY_USERATTRIBUTESET;
+char *CIL_KEY_SENSITIVITY;
+char *CIL_KEY_CATEGORY;
+char *CIL_KEY_CATSET;
+char *CIL_KEY_LEVEL;
+char *CIL_KEY_LEVELRANGE;
+char *CIL_KEY_CLASS;
+char *CIL_KEY_IPADDR;
+char *CIL_KEY_MAP_CLASS;
+char *CIL_KEY_CLASSPERMISSION;
+char *CIL_KEY_BOOL;
+char *CIL_KEY_STRING;
+char *CIL_KEY_NAME;
+char *CIL_KEY_SOURCE;
+char *CIL_KEY_TARGET;
+char *CIL_KEY_LOW;
+char *CIL_KEY_HIGH;
+char *CIL_KEY_LOW_HIGH;
+char *CIL_KEY_HANDLEUNKNOWN;
+char *CIL_KEY_HANDLEUNKNOWN_ALLOW;
+char *CIL_KEY_HANDLEUNKNOWN_DENY;
+char *CIL_KEY_HANDLEUNKNOWN_REJECT;
+char *CIL_KEY_MACRO;
+char *CIL_KEY_IN;
+char *CIL_KEY_MLS;
+char *CIL_KEY_DEFAULTRANGE;
+char *CIL_KEY_BLOCKINHERIT;
+char *CIL_KEY_BLOCKABSTRACT;
+char *CIL_KEY_CLASSORDER;
+char *CIL_KEY_CLASSMAPPING;
+char *CIL_KEY_CLASSPERMISSIONSET;
+char *CIL_KEY_COMMON;
+char *CIL_KEY_CLASSCOMMON;
+char *CIL_KEY_SID;
+char *CIL_KEY_SIDCONTEXT;
+char *CIL_KEY_SIDORDER;
+char *CIL_KEY_USERLEVEL;
+char *CIL_KEY_USERRANGE;
+char *CIL_KEY_USERBOUNDS;
+char *CIL_KEY_USERPREFIX;
+char *CIL_KEY_SELINUXUSER;
+char *CIL_KEY_SELINUXUSERDEFAULT;
+char *CIL_KEY_TYPEATTRIBUTE;
+char *CIL_KEY_TYPEATTRIBUTESET;
+char *CIL_KEY_TYPEALIAS;
+char *CIL_KEY_TYPEALIASACTUAL;
+char *CIL_KEY_TYPEBOUNDS;
+char *CIL_KEY_TYPEPERMISSIVE;
+char *CIL_KEY_RANGETRANSITION;
+char *CIL_KEY_USERROLE;
+char *CIL_KEY_ROLETYPE;
+char *CIL_KEY_ROLETRANSITION;
+char *CIL_KEY_ROLEALLOW;
+char *CIL_KEY_ROLEATTRIBUTE;
+char *CIL_KEY_ROLEATTRIBUTESET;
+char *CIL_KEY_ROLEBOUNDS;
+char *CIL_KEY_BOOLEANIF;
+char *CIL_KEY_NEVERALLOW;
+char *CIL_KEY_TYPEMEMBER;
+char *CIL_KEY_SENSALIAS;
+char *CIL_KEY_SENSALIASACTUAL;
+char *CIL_KEY_CATALIAS;
+char *CIL_KEY_CATALIASACTUAL;
+char *CIL_KEY_CATORDER;
+char *CIL_KEY_SENSITIVITYORDER;
+char *CIL_KEY_SENSCAT;
+char *CIL_KEY_CONSTRAIN;
+char *CIL_KEY_MLSCONSTRAIN;
+char *CIL_KEY_VALIDATETRANS;
+char *CIL_KEY_MLSVALIDATETRANS;
+char *CIL_KEY_CONTEXT;
+char *CIL_KEY_FILECON;
+char *CIL_KEY_PORTCON;
+char *CIL_KEY_NODECON;
+char *CIL_KEY_GENFSCON;
+char *CIL_KEY_NETIFCON;
+char *CIL_KEY_PIRQCON;
+char *CIL_KEY_IOMEMCON;
+char *CIL_KEY_IOPORTCON;
+char *CIL_KEY_PCIDEVICECON;
+char *CIL_KEY_DEVICETREECON;
+char *CIL_KEY_FSUSE;
+char *CIL_KEY_POLICYCAP;
+char *CIL_KEY_OPTIONAL;
+char *CIL_KEY_DEFAULTUSER;
+char *CIL_KEY_DEFAULTROLE;
+char *CIL_KEY_DEFAULTTYPE;
+char *CIL_KEY_ROOT;
+char *CIL_KEY_NODE;
+char *CIL_KEY_PERM;
+char *CIL_KEY_ALLOWX;
+char *CIL_KEY_AUDITALLOWX;
+char *CIL_KEY_DONTAUDITX;
+char *CIL_KEY_NEVERALLOWX;
+char *CIL_KEY_PERMISSIONX;
+char *CIL_KEY_IOCTL;
+char *CIL_KEY_UNORDERED;
+char *CIL_KEY_SRC_INFO;
+char *CIL_KEY_SRC_CIL;
+char *CIL_KEY_SRC_HLL;
+
+/*
+ Symbol Table Array Indices
+*/
+enum cil_sym_index {
+ CIL_SYM_BLOCKS = 0,
+ CIL_SYM_USERS,
+ CIL_SYM_ROLES,
+ CIL_SYM_TYPES,
+ CIL_SYM_COMMONS,
+ CIL_SYM_CLASSES,
+ CIL_SYM_CLASSPERMSETS,
+ CIL_SYM_BOOLS,
+ CIL_SYM_TUNABLES,
+ CIL_SYM_SENS,
+ CIL_SYM_CATS,
+ CIL_SYM_SIDS,
+ CIL_SYM_CONTEXTS,
+ CIL_SYM_LEVELS,
+ CIL_SYM_LEVELRANGES,
+ CIL_SYM_POLICYCAPS,
+ CIL_SYM_IPADDRS,
+ CIL_SYM_NAMES,
+ CIL_SYM_PERMX,
+ CIL_SYM_NUM,
+ CIL_SYM_UNKNOWN,
+ CIL_SYM_PERMS // Special case for permissions. This symtab is not included in arrays
+};
+
+enum cil_sym_array {
+ CIL_SYM_ARRAY_ROOT = 0,
+ CIL_SYM_ARRAY_BLOCK,
+ CIL_SYM_ARRAY_IN,
+ CIL_SYM_ARRAY_MACRO,
+ CIL_SYM_ARRAY_CONDBLOCK,
+ CIL_SYM_ARRAY_NUM
+};
+
+extern int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM];
+
+#define CIL_CLASS_SYM_SIZE 256
+
+struct cil_db {
+ struct cil_tree *parse;
+ struct cil_tree *ast;
+ struct cil_type *selftype;
+ struct cil_list *sidorder;
+ struct cil_list *classorder;
+ struct cil_list *catorder;
+ struct cil_list *sensitivityorder;
+ struct cil_sort *netifcon;
+ struct cil_sort *genfscon;
+ struct cil_sort *filecon;
+ struct cil_sort *nodecon;
+ struct cil_sort *portcon;
+ struct cil_sort *pirqcon;
+ struct cil_sort *iomemcon;
+ struct cil_sort *ioportcon;
+ struct cil_sort *pcidevicecon;
+ struct cil_sort *devicetreecon;
+ struct cil_sort *fsuse;
+ struct cil_list *userprefixes;
+ struct cil_list *selinuxusers;
+ struct cil_list *names;
+ int num_types_and_attrs;
+ int num_classes;
+ int num_cats;
+ int num_types;
+ int num_roles;
+ int num_users;
+ struct cil_type **val_to_type;
+ struct cil_role **val_to_role;
+ struct cil_user **val_to_user;
+ int disable_dontaudit;
+ int disable_neverallow;
+ int preserve_tunables;
+ int handle_unknown;
+ int mls;
+ int target_platform;
+ int policy_version;
+};
+
+struct cil_root {
+ symtab_t symtab[CIL_SYM_NUM];
+};
+
+struct cil_sort {
+ enum cil_flavor flavor;
+ uint32_t count;
+ uint32_t index;
+ void **array;
+};
+
+struct cil_block {
+ struct cil_symtab_datum datum;
+ symtab_t symtab[CIL_SYM_NUM];
+ uint16_t is_abstract;
+ struct cil_list *bi_nodes;
+};
+
+struct cil_blockinherit {
+ char *block_str;
+ struct cil_block *block;
+};
+
+struct cil_blockabstract {
+ char *block_str;
+};
+
+struct cil_in {
+ symtab_t symtab[CIL_SYM_NUM];
+ char *block_str;
+};
+
+struct cil_optional {
+ struct cil_symtab_datum datum;
+ int enabled;
+};
+
+struct cil_perm {
+ struct cil_symtab_datum datum;
+ unsigned int value;
+ struct cil_list *classperms; /* Only used for map perms */
+};
+
+struct cil_class {
+ struct cil_symtab_datum datum;
+ symtab_t perms;
+ unsigned int num_perms;
+ struct cil_class *common; /* Only used for kernel class */
+ uint32_t ordered; /* Only used for kernel class */
+};
+
+struct cil_classorder {
+ struct cil_list *class_list_str;
+};
+
+struct cil_classperms_set {
+ char *set_str;
+ struct cil_classpermission *set;
+};
+
+struct cil_classperms {
+ char *class_str;
+ struct cil_class *class;
+ struct cil_list *perm_strs;
+ struct cil_list *perms;
+};
+
+struct cil_classpermission {
+ struct cil_symtab_datum datum;
+ struct cil_list *classperms;
+};
+
+struct cil_classpermissionset {
+ char *set_str;
+ struct cil_list *classperms;
+};
+
+struct cil_classmapping {
+ char *map_class_str;
+ char *map_perm_str;
+ struct cil_list *classperms;
+};
+
+struct cil_classcommon {
+ char *class_str;
+ char *common_str;
+};
+
+struct cil_alias {
+ struct cil_symtab_datum datum;
+ void *actual;
+};
+
+struct cil_aliasactual {
+ char *alias_str;
+ char *actual_str;
+};
+
+struct cil_sid {
+ struct cil_symtab_datum datum;
+ struct cil_context *context;
+ uint32_t ordered;
+};
+
+struct cil_sidcontext {
+ char *sid_str;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_sidorder {
+ struct cil_list *sid_list_str;
+};
+
+struct cil_user {
+ struct cil_symtab_datum datum;
+ struct cil_user *bounds;
+ ebitmap_t *roles;
+ struct cil_level *dftlevel;
+ struct cil_levelrange *range;
+ int value;
+};
+
+struct cil_userattribute {
+ struct cil_symtab_datum datum;
+ struct cil_list *expr_list;
+ ebitmap_t *users;
+};
+
+struct cil_userattributeset {
+ char *attr_str;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_userrole {
+ char *user_str;
+ void *user;
+ char *role_str;
+ void *role;
+};
+
+struct cil_userlevel {
+ char *user_str;
+ char *level_str;
+ struct cil_level *level;
+};
+
+struct cil_userrange {
+ char *user_str;
+ char *range_str;
+ struct cil_levelrange *range;
+};
+
+struct cil_userprefix {
+ char *user_str;
+ struct cil_user *user;
+ char *prefix_str;
+};
+
+struct cil_selinuxuser {
+ char *name_str;
+ char *user_str;
+ struct cil_user *user;
+ char *range_str;
+ struct cil_levelrange *range;
+};
+
+struct cil_role {
+ struct cil_symtab_datum datum;
+ struct cil_role *bounds;
+ ebitmap_t *types;
+ int value;
+};
+
+struct cil_roleattribute {
+ struct cil_symtab_datum datum;
+ struct cil_list *expr_list;
+ ebitmap_t *roles;
+};
+
+struct cil_roleattributeset {
+ char *attr_str;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_roletype {
+ char *role_str;
+ void *role; /* role or attribute */
+ char *type_str;
+ void *type; /* type, alias, or attribute */
+};
+
+struct cil_type {
+ struct cil_symtab_datum datum;
+ struct cil_type *bounds;
+ int value;
+};
+
+struct cil_typeattribute {
+ struct cil_symtab_datum datum;
+ struct cil_list *expr_list;
+ ebitmap_t *types;
+ int used; // whether or not this typeattribute was used and should be added to the binary
+};
+
+struct cil_typeattributeset {
+ char *attr_str;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_typepermissive {
+ char *type_str;
+ void *type; /* type or alias */
+};
+
+struct cil_name {
+ struct cil_symtab_datum datum;
+ char *name_str;
+};
+
+struct cil_nametypetransition {
+ char *src_str;
+ void *src; /* type, alias, or attribute */
+ char *tgt_str;
+ void *tgt; /* type, alias, or attribute */
+ char *obj_str;
+ struct cil_class *obj;
+ char *name_str;
+ struct cil_name *name;
+ char *result_str;
+ void *result; /* type or alias */
+
+};
+
+struct cil_rangetransition {
+ char *src_str;
+ void *src; /* type, alias, or attribute */
+ char *exec_str;
+ void *exec; /* type, alias, or attribute */
+ char *obj_str;
+ struct cil_class *obj;
+ char *range_str;
+ struct cil_levelrange *range;
+};
+
+struct cil_bool {
+ struct cil_symtab_datum datum;
+ uint16_t value;
+};
+
+struct cil_tunable {
+ struct cil_symtab_datum datum;
+ uint16_t value;
+};
+
+#define CIL_AVRULE_ALLOWED 1
+#define CIL_AVRULE_AUDITALLOW 2
+#define CIL_AVRULE_DONTAUDIT 8
+#define CIL_AVRULE_NEVERALLOW 128
+#define CIL_AVRULE_AV (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+struct cil_avrule {
+ int is_extended;
+ uint32_t rule_kind;
+ char *src_str;
+ void *src; /* type, alias, or attribute */
+ char *tgt_str;
+ void *tgt; /* type, alias, or attribute */
+ union {
+ struct cil_list *classperms;
+ struct {
+ char *permx_str;
+ struct cil_permissionx *permx;
+ } x;
+ } perms;
+};
+
+#define CIL_PERMX_KIND_IOCTL 1
+struct cil_permissionx {
+ struct cil_symtab_datum datum;
+ uint32_t kind;
+ char *obj_str;
+ struct cil_class *obj;
+ struct cil_list *expr_str;
+ ebitmap_t *perms;
+};
+
+#define CIL_TYPE_TRANSITION 16
+#define CIL_TYPE_MEMBER 32
+#define CIL_TYPE_CHANGE 64
+#define CIL_AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+struct cil_type_rule {
+ uint32_t rule_kind;
+ char *src_str;
+ void *src; /* type, alias, or attribute */
+ char *tgt_str;
+ void *tgt; /* type, alias, or attribute */
+ char *obj_str;
+ struct cil_class *obj;
+ char *result_str;
+ void *result; /* type or alias */
+};
+
+struct cil_roletransition {
+ char *src_str;
+ struct cil_role *src;
+ char *tgt_str;
+ void *tgt; /* type, alias, or attribute */
+ char *obj_str;
+ struct cil_class *obj;
+ char *result_str;
+ struct cil_role *result;
+};
+
+struct cil_roleallow {
+ char *src_str;
+ void *src; /* role or attribute */
+ char *tgt_str;
+ void *tgt; /* role or attribute */
+};
+
+struct cil_sens {
+ struct cil_symtab_datum datum;
+ struct cil_list *cats_list;
+ uint32_t ordered;
+};
+
+struct cil_sensorder {
+ struct cil_list *sens_list_str;
+};
+
+struct cil_cat {
+ struct cil_symtab_datum datum;
+ uint32_t ordered;
+ int value;
+};
+
+struct cil_cats {
+ uint32_t evaluated;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_catset {
+ struct cil_symtab_datum datum;
+ struct cil_cats *cats;
+};
+
+struct cil_catorder {
+ struct cil_list *cat_list_str;
+};
+
+struct cil_senscat {
+ char *sens_str;
+ struct cil_cats *cats;
+};
+
+struct cil_level {
+ struct cil_symtab_datum datum;
+ char *sens_str;
+ struct cil_sens *sens;
+ struct cil_cats *cats;
+};
+
+struct cil_levelrange {
+ struct cil_symtab_datum datum;
+ char *low_str;
+ struct cil_level *low;
+ char *high_str;
+ struct cil_level *high;
+};
+
+struct cil_context {
+ struct cil_symtab_datum datum;
+ char *user_str;
+ struct cil_user *user;
+ char *role_str;
+ struct cil_role *role;
+ char *type_str;
+ void *type; /* type or alias */
+ char *range_str;
+ struct cil_levelrange *range;
+};
+
+enum cil_filecon_types {
+ CIL_FILECON_FILE = 1,
+ CIL_FILECON_DIR,
+ CIL_FILECON_CHAR,
+ CIL_FILECON_BLOCK,
+ CIL_FILECON_SOCKET,
+ CIL_FILECON_PIPE,
+ CIL_FILECON_SYMLINK,
+ CIL_FILECON_ANY
+};
+
+struct cil_filecon {
+ char *path_str;
+ enum cil_filecon_types type;
+ char *context_str;
+ struct cil_context *context;
+};
+
+enum cil_protocol {
+ CIL_PROTOCOL_UDP = 1,
+ CIL_PROTOCOL_TCP,
+ CIL_PROTOCOL_DCCP
+};
+
+struct cil_portcon {
+ enum cil_protocol proto;
+ uint32_t port_low;
+ uint32_t port_high;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_nodecon {
+ char *addr_str;
+ struct cil_ipaddr *addr;
+ char *mask_str;
+ struct cil_ipaddr *mask;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_ipaddr {
+ struct cil_symtab_datum datum;
+ int family;
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } ip;
+};
+
+struct cil_genfscon {
+ char *fs_str;
+ char *path_str;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_netifcon {
+ char *interface_str;
+ char *if_context_str;
+ struct cil_context *if_context;
+ char *packet_context_str;
+ struct cil_context *packet_context;
+ char *context_str;
+};
+
+struct cil_pirqcon {
+ uint32_t pirq;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_iomemcon {
+ uint64_t iomem_low;
+ uint64_t iomem_high;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_ioportcon {
+ uint32_t ioport_low;
+ uint32_t ioport_high;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_pcidevicecon {
+ uint32_t dev;
+ char *context_str;
+ struct cil_context *context;
+};
+
+struct cil_devicetreecon {
+ char *path;
+ char *context_str;
+ struct cil_context *context;
+};
+
+
+/* Ensure that CIL uses the same values as sepol services.h */
+enum cil_fsuse_types {
+ CIL_FSUSE_XATTR = SECURITY_FS_USE_XATTR,
+ CIL_FSUSE_TASK = SECURITY_FS_USE_TASK,
+ CIL_FSUSE_TRANS = SECURITY_FS_USE_TRANS
+};
+
+struct cil_fsuse {
+ enum cil_fsuse_types type;
+ char *fs_str;
+ char *context_str;
+ struct cil_context *context;
+};
+
+#define CIL_MLS_LEVELS "l1 l2 h1 h2"
+#define CIL_CONSTRAIN_KEYS "t1 t2 r1 r2 u1 u2"
+#define CIL_MLSCONSTRAIN_KEYS CIL_MLS_LEVELS CIL_CONSTRAIN_KEYS
+#define CIL_CONSTRAIN_OPER "== != eq dom domby incomp not and or"
+struct cil_constrain {
+ struct cil_list *classperms;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_validatetrans {
+ char *class_str;
+ struct cil_class *class;
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_param {
+ char *str;
+ enum cil_flavor flavor;
+};
+
+struct cil_macro {
+ struct cil_symtab_datum datum;
+ symtab_t symtab[CIL_SYM_NUM];
+ struct cil_list *params;
+};
+
+struct cil_args {
+ char *arg_str;
+ struct cil_symtab_datum *arg;
+ char *param_str;
+ enum cil_flavor flavor;
+};
+
+struct cil_call {
+ char *macro_str;
+ struct cil_macro *macro;
+ struct cil_tree *args_tree;
+ struct cil_list *args;
+ int copied;
+};
+
+#define CIL_TRUE 1
+#define CIL_FALSE 0
+
+struct cil_condblock {
+ enum cil_flavor flavor;
+ symtab_t symtab[CIL_SYM_NUM];
+};
+
+struct cil_booleanif {
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+ int preserved_tunable;
+};
+
+struct cil_tunableif {
+ struct cil_list *str_expr;
+ struct cil_list *datum_expr;
+};
+
+struct cil_policycap {
+ struct cil_symtab_datum datum;
+};
+
+struct cil_bounds {
+ char *parent_str;
+ char *child_str;
+};
+
+/* Ensure that CIL uses the same values as sepol policydb.h */
+enum cil_default_object {
+ CIL_DEFAULT_SOURCE = DEFAULT_SOURCE,
+ CIL_DEFAULT_TARGET = DEFAULT_TARGET,
+};
+
+/* Default labeling behavior for users, roles, and types */
+struct cil_default {
+ enum cil_flavor flavor;
+ struct cil_list *class_strs;
+ struct cil_list *class_datums;
+ enum cil_default_object object;
+};
+
+/* Ensure that CIL uses the same values as sepol policydb.h */
+enum cil_default_object_range {
+ CIL_DEFAULT_SOURCE_LOW = DEFAULT_SOURCE_LOW,
+ CIL_DEFAULT_SOURCE_HIGH = DEFAULT_SOURCE_HIGH,
+ CIL_DEFAULT_SOURCE_LOW_HIGH = DEFAULT_SOURCE_LOW_HIGH,
+ CIL_DEFAULT_TARGET_LOW = DEFAULT_TARGET_LOW,
+ CIL_DEFAULT_TARGET_HIGH = DEFAULT_TARGET_HIGH,
+ CIL_DEFAULT_TARGET_LOW_HIGH = DEFAULT_TARGET_LOW_HIGH,
+};
+
+/* Default labeling behavior for range */
+struct cil_defaultrange {
+ struct cil_list *class_strs;
+ struct cil_list *class_datums;
+ enum cil_default_object_range object_range;
+};
+
+struct cil_handleunknown {
+ int handle_unknown;
+};
+
+struct cil_mls {
+ int value;
+};
+
+struct cil_src_info {
+ int is_cil;
+ char *path;
+};
+
+void cil_db_init(struct cil_db **db);
+void cil_db_destroy(struct cil_db **db);
+
+void cil_root_init(struct cil_root **root);
+void cil_root_destroy(struct cil_root *root);
+
+void cil_destroy_data(void **data, enum cil_flavor flavor);
+
+int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *index);
+const char * cil_node_to_string(struct cil_tree_node *node);
+
+int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size);
+int cil_selinuxusers_to_string(struct cil_db *db, char **out, size_t *size);
+int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size);
+
+void cil_symtab_array_init(symtab_t symtab[], int symtab_sizes[CIL_SYM_NUM]);
+void cil_symtab_array_destroy(symtab_t symtab[]);
+void cil_destroy_ast_symtabs(struct cil_tree_node *root);
+int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_sym_index sym_index);
+
+void cil_sort_init(struct cil_sort **sort);
+void cil_sort_destroy(struct cil_sort **sort);
+void cil_netifcon_init(struct cil_netifcon **netifcon);
+void cil_context_init(struct cil_context **context);
+void cil_level_init(struct cil_level **level);
+void cil_levelrange_init(struct cil_levelrange **lvlrange);
+void cil_sens_init(struct cil_sens **sens);
+void cil_block_init(struct cil_block **block);
+void cil_blockinherit_init(struct cil_blockinherit **inherit);
+void cil_blockabstract_init(struct cil_blockabstract **abstract);
+void cil_in_init(struct cil_in **in);
+void cil_class_init(struct cil_class **class);
+void cil_classorder_init(struct cil_classorder **classorder);
+void cil_classcommon_init(struct cil_classcommon **classcommon);
+void cil_sid_init(struct cil_sid **sid);
+void cil_sidcontext_init(struct cil_sidcontext **sidcontext);
+void cil_sidorder_init(struct cil_sidorder **sidorder);
+void cil_userrole_init(struct cil_userrole **userrole);
+void cil_userprefix_init(struct cil_userprefix **userprefix);
+void cil_selinuxuser_init(struct cil_selinuxuser **selinuxuser);
+void cil_roleattribute_init(struct cil_roleattribute **attribute);
+void cil_roleattributeset_init(struct cil_roleattributeset **attrset);
+void cil_roletype_init(struct cil_roletype **roletype);
+void cil_typeattribute_init(struct cil_typeattribute **attribute);
+void cil_typeattributeset_init(struct cil_typeattributeset **attrset);
+void cil_alias_init(struct cil_alias **alias);
+void cil_aliasactual_init(struct cil_aliasactual **aliasactual);
+void cil_typepermissive_init(struct cil_typepermissive **typeperm);
+void cil_name_init(struct cil_name **name);
+void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans);
+void cil_rangetransition_init(struct cil_rangetransition **rangetrans);
+void cil_bool_init(struct cil_bool **cilbool);
+void cil_boolif_init(struct cil_booleanif **bif);
+void cil_condblock_init(struct cil_condblock **cb);
+void cil_tunable_init(struct cil_tunable **ciltun);
+void cil_tunif_init(struct cil_tunableif **tif);
+void cil_avrule_init(struct cil_avrule **avrule);
+void cil_permissionx_init(struct cil_permissionx **permx);
+void cil_type_rule_init(struct cil_type_rule **type_rule);
+void cil_roletransition_init(struct cil_roletransition **roletrans);
+void cil_roleallow_init(struct cil_roleallow **role_allow);
+void cil_catset_init(struct cil_catset **catset);
+void cil_cats_init(struct cil_cats **cats);
+void cil_senscat_init(struct cil_senscat **senscat);
+void cil_filecon_init(struct cil_filecon **filecon);
+void cil_portcon_init(struct cil_portcon **portcon);
+void cil_nodecon_init(struct cil_nodecon **nodecon);
+void cil_genfscon_init(struct cil_genfscon **genfscon);
+void cil_pirqcon_init(struct cil_pirqcon **pirqcon);
+void cil_iomemcon_init(struct cil_iomemcon **iomemcon);
+void cil_ioportcon_init(struct cil_ioportcon **ioportcon);
+void cil_pcidevicecon_init(struct cil_pcidevicecon **pcidevicecon);
+void cil_devicetreecon_init(struct cil_devicetreecon **devicetreecon);
+void cil_fsuse_init(struct cil_fsuse **fsuse);
+void cil_constrain_init(struct cil_constrain **constrain);
+void cil_validatetrans_init(struct cil_validatetrans **validtrans);
+void cil_ipaddr_init(struct cil_ipaddr **ipaddr);
+void cil_perm_init(struct cil_perm **perm);
+void cil_classpermission_init(struct cil_classpermission **cp);
+void cil_classpermissionset_init(struct cil_classpermissionset **cps);
+void cil_classperms_set_init(struct cil_classperms_set **cp_set);
+void cil_classperms_init(struct cil_classperms **cp);
+void cil_classmapping_init(struct cil_classmapping **mapping);
+void cil_user_init(struct cil_user **user);
+void cil_userlevel_init(struct cil_userlevel **usrlvl);
+void cil_userrange_init(struct cil_userrange **userrange);
+void cil_role_init(struct cil_role **role);
+void cil_type_init(struct cil_type **type);
+void cil_cat_init(struct cil_cat **cat);
+void cil_catorder_init(struct cil_catorder **catorder);
+void cil_sensorder_init(struct cil_sensorder **sensorder);
+void cil_args_init(struct cil_args **args);
+void cil_call_init(struct cil_call **call);
+void cil_optional_init(struct cil_optional **optional);
+void cil_param_init(struct cil_param **param);
+void cil_macro_init(struct cil_macro **macro);
+void cil_policycap_init(struct cil_policycap **policycap);
+void cil_bounds_init(struct cil_bounds **bounds);
+void cil_default_init(struct cil_default **def);
+void cil_defaultrange_init(struct cil_defaultrange **def);
+void cil_handleunknown_init(struct cil_handleunknown **unk);
+void cil_mls_init(struct cil_mls **mls);
+void cil_src_info_init(struct cil_src_info **info);
+void cil_userattribute_init(struct cil_userattribute **attribute);
+void cil_userattributeset_init(struct cil_userattributeset **attrset);
+
+#endif
diff --git a/libsepol/cil/src/cil_lexer.h b/libsepol/cil/src/cil_lexer.h
new file mode 100644
index 0000000..ab555d8
--- /dev/null
+++ b/libsepol/cil/src/cil_lexer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_LEXER_H_
+#define CIL_LEXER_H_
+
+#include <stdint.h>
+
+#define OPAREN 1
+#define CPAREN 2
+#define SYMBOL 3
+#define QSTRING 4
+#define COMMENT 5
+#define HLL_LINEMARK 6
+#define NEWLINE 7
+#define END_OF_FILE 8
+#define UNKNOWN 9
+
+struct token {
+ uint32_t type;
+ char * value;
+ uint32_t line;
+};
+
+int cil_lexer_setup(char *buffer, uint32_t size);
+void cil_lexer_destroy(void);
+int cil_lexer_next(struct token *tok);
+
+#endif /* CIL_LEXER_H_ */
diff --git a/libsepol/cil/src/cil_lexer.l b/libsepol/cil/src/cil_lexer.l
new file mode 100644
index 0000000..e28c33e
--- /dev/null
+++ b/libsepol/cil/src/cil_lexer.l
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+%{
+ #include <stdint.h>
+ #include <sepol/errcodes.h>
+ #include "cil_internal.h"
+ #include "cil_lexer.h"
+ #include "cil_log.h"
+ #include "cil_mem.h"
+ char *value = NULL;
+ int line = 1;
+%}
+
+%option nounput
+%option noinput
+%option noyywrap
+%option prefix="cil_yy"
+
+digit [0-9]
+alpha [a-zA-Z]
+spec_char [\[\]\.\@\=\/\*\-\_\$\%\+\-\!\|\&\^\:\~\`\#\{\}\'\<\>\?\,]
+symbol ({digit}|{alpha}|{spec_char})+
+white [ \t]
+newline [\n\r]
+qstring \"[^"\n]*\"
+hll_lm ^;;\*
+comment ;
+
+%%
+{newline} line++; return NEWLINE;
+{hll_lm} value=yytext; return HLL_LINEMARK;
+{comment} value=yytext; return COMMENT;
+"(" value=yytext; return OPAREN;
+")" value=yytext; return CPAREN;
+{symbol} value=yytext; return SYMBOL;
+{white} ;
+{qstring} value=yytext; return QSTRING;
+<<EOF>> return END_OF_FILE;
+. value=yytext; return UNKNOWN;
+%%
+
+int cil_lexer_setup(char *buffer, uint32_t size)
+{
+ size = (yy_size_t)size;
+ if (yy_scan_buffer(buffer, size) == NULL) {
+ cil_log(CIL_INFO, "Lexer failed to setup buffer\n");
+ return SEPOL_ERR;
+ }
+
+ line = 1;
+
+ return SEPOL_OK;
+}
+
+void cil_lexer_destroy(void)
+{
+ yylex_destroy();
+}
+
+int cil_lexer_next(struct token *tok)
+{
+ tok->type = yylex();
+ tok->value = value;
+ tok->line = line;
+
+ return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_list.c b/libsepol/cil/src/cil_list.c
new file mode 100644
index 0000000..4e7843c
--- /dev/null
+++ b/libsepol/cil/src/cil_list.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_list_error(const char* msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ cil_vlog(CIL_ERR, msg, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void cil_list_init(struct cil_list **list, enum cil_flavor flavor)
+{
+ struct cil_list *new_list = cil_malloc(sizeof(*new_list));
+ new_list->head = NULL;
+ new_list->tail = NULL;
+ new_list->flavor = flavor;
+ *list = new_list;
+}
+
+void cil_list_destroy(struct cil_list **list, unsigned destroy_data)
+{
+ if (*list == NULL) {
+ return;
+ }
+
+ struct cil_list_item *item = (*list)->head;
+ struct cil_list_item *next = NULL;
+ while (item != NULL)
+ {
+ next = item->next;
+ if (item->flavor == CIL_LIST) {
+ cil_list_destroy((struct cil_list**)&(item->data), destroy_data);
+ free(item);
+ } else {
+ cil_list_item_destroy(&item, destroy_data);
+ }
+ item = next;
+ }
+ free(*list);
+ *list = NULL;
+}
+
+void cil_list_item_init(struct cil_list_item **item)
+{
+ struct cil_list_item *new_item = cil_malloc(sizeof(*new_item));
+ new_item->next = NULL;
+ new_item->flavor = CIL_NONE;
+ new_item->data = NULL;
+
+ *item = new_item;
+}
+
+void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data)
+{
+ if (destroy_data) {
+ cil_destroy_data(&(*item)->data, (*item)->flavor);
+ }
+ free(*item);
+ *item = NULL;
+}
+
+void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data)
+{
+ struct cil_list_item *item;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to append data to a NULL list");
+ }
+
+ cil_list_item_init(&item);
+ item->flavor = flavor;
+ item->data = data;
+
+ if (list->tail == NULL) {
+ list->head = item;
+ list->tail = item;
+ return;
+ }
+
+ list->tail->next = item;
+ list->tail = item;
+}
+
+void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data)
+{
+ struct cil_list_item *item;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to prepend data to a NULL list");
+ }
+
+ cil_list_item_init(&item);
+ item->flavor = flavor;
+ item->data = data;
+
+ if (list->tail == NULL) {
+ list->head = item;
+ list->tail = item;
+ return;
+ }
+
+ item->next = list->head;
+ list->head = item;
+}
+
+struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data)
+{
+ struct cil_list_item *item;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to append data to a NULL list");
+ }
+
+ if (curr == NULL) {
+ /* Insert at the front of the list */
+ cil_list_prepend(list, flavor, data);
+ return list->head;
+ }
+
+ if (curr == list->tail) {
+ cil_list_append(list, flavor, data);
+ return list->tail;
+ }
+
+ cil_list_item_init(&item);
+ item->flavor = flavor;
+ item->data = data;
+ item->next = curr->next;
+
+ curr->next = item;
+
+ return item;
+}
+
+void cil_list_append_item(struct cil_list *list, struct cil_list_item *item)
+{
+ struct cil_list_item *last = item;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to append an item to a NULL list");
+ }
+
+ if (item == NULL) {
+ cil_list_error("Attempt to append a NULL item to a list");
+ }
+
+ while (last->next != NULL) {
+ last = last->next;
+ }
+
+ if (list->tail == NULL) {
+ list->head = item;
+ list->tail = last;
+ return;
+ }
+
+ list->tail->next = item;
+ list->tail = last;
+
+}
+
+void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item)
+{
+ struct cil_list_item *last = item;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to prepend an item to a NULL list");
+ }
+
+ if (item == NULL) {
+ cil_list_error("Attempt to prepend a NULL item to a list");
+ }
+
+ while (last->next != NULL) {
+ last = last->next;
+ }
+
+ if (list->tail == NULL) {
+ list->head = item;
+ list->tail = last;
+ return;
+ }
+
+ last->next = list->head;
+ list->head = item;
+}
+
+void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data)
+{
+ struct cil_list_item *item;
+ struct cil_list_item *previous = NULL;
+
+ if (list == NULL) {
+ cil_list_error("Attempt to remove data from a NULL list");
+ }
+
+ cil_list_for_each(item, list) {
+ if (item->data == data && item->flavor == flavor) {
+ if (previous == NULL) {
+ list->head = item->next;
+ } else {
+ previous->next = item->next;
+ }
+ if (item->next == NULL) {
+ list->tail = previous;
+ }
+ cil_list_item_destroy(&item, destroy_data);
+ break;
+ }
+ previous = item;
+ }
+}
+
+int cil_list_contains(struct cil_list *list, void *data)
+{
+ struct cil_list_item *curr = NULL;
+
+ cil_list_for_each(curr, list) {
+ if (curr->data == data) {
+ return CIL_TRUE;
+ }
+ }
+
+ return CIL_FALSE;
+}
+
+int cil_list_match_any(struct cil_list *l1, struct cil_list *l2)
+{
+ struct cil_list_item *i1;
+ struct cil_list_item *i2;
+
+ cil_list_for_each(i1, l1) {
+ cil_list_for_each(i2, l2) {
+ if (i1->data == i2->data && i1->flavor == i2->flavor) {
+ return CIL_TRUE;
+ }
+ }
+ }
+
+ return CIL_FALSE;
+}
diff --git a/libsepol/cil/src/cil_list.h b/libsepol/cil/src/cil_list.h
new file mode 100644
index 0000000..6b4708a
--- /dev/null
+++ b/libsepol/cil/src/cil_list.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_LIST_H_
+#define CIL_LIST_H_
+
+#include "cil_flavor.h"
+
+struct cil_list {
+ struct cil_list_item *head;
+ struct cil_list_item *tail;
+ enum cil_flavor flavor;
+};
+
+struct cil_list_item {
+ struct cil_list_item *next;
+ enum cil_flavor flavor;
+ void *data;
+};
+
+#define cil_list_for_each(item, list) \
+ for (item = (list)->head; item != NULL; item = item->next)
+
+
+void cil_list_init(struct cil_list **list, enum cil_flavor flavor);
+void cil_list_destroy (struct cil_list **list, unsigned destroy_data);
+void cil_list_item_init(struct cil_list_item **item);
+void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data);
+void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data);
+void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data);
+void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data);
+struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data);
+void cil_list_append_item(struct cil_list *list, struct cil_list_item *item);
+void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item);
+int cil_list_contains(struct cil_list *list, void *data);
+int cil_list_match_any(struct cil_list *l1, struct cil_list *l2);
+
+#endif
diff --git a/libsepol/cil/src/cil_log.c b/libsepol/cil/src/cil_log.c
new file mode 100644
index 0000000..b222b15
--- /dev/null
+++ b/libsepol/cil/src/cil_log.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <cil/cil.h>
+#include "cil_log.h"
+
+static enum cil_log_level cil_log_level = CIL_ERR;
+
+void cil_default_log_handler(__attribute__((unused)) int lvl, char *msg)
+{
+ fprintf(stderr, "%s", msg);
+}
+
+void (*cil_log_handler)(int lvl, char *msg) = &cil_default_log_handler;
+
+void cil_set_log_handler(void (*handler)(int lvl, char *msg))
+{
+ cil_log_handler = handler;
+}
+
+__attribute__ ((format (printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args)
+{
+ if (cil_log_level >= lvl) {
+ char buff[MAX_LOG_SIZE];
+ vsnprintf(buff, MAX_LOG_SIZE, msg, args);
+ (*cil_log_handler)(cil_log_level, buff);
+ }
+}
+
+__attribute__ ((format (printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ cil_vlog(lvl, msg, args);
+ va_end(args);
+}
+
+void cil_set_log_level(enum cil_log_level lvl)
+{
+ cil_log_level = lvl;
+}
diff --git a/libsepol/cil/src/cil_log.h b/libsepol/cil/src/cil_log.h
new file mode 100644
index 0000000..4112aaf
--- /dev/null
+++ b/libsepol/cil/src/cil_log.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+#ifndef CIL_LOG_H_
+#define CIL_LOG_H_
+
+#include <stdlib.h>
+#include <cil/cil.h>
+
+#define MAX_LOG_SIZE 512
+
+__attribute__ ((format(printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args);
+__attribute__ ((format(printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...);
+
+#endif // CIL_LOG_H_
diff --git a/libsepol/cil/src/cil_mem.c b/libsepol/cil/src/cil_mem.c
new file mode 100644
index 0000000..12c59be
--- /dev/null
+++ b/libsepol/cil/src/cil_mem.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "cil_log.h"
+
+__attribute__((noreturn)) void cil_default_mem_error_handler(void)
+{
+ cil_log(CIL_ERR, "Failed to allocate memory\n");
+ exit(1);
+}
+
+void (*cil_mem_error_handler)(void) = &cil_default_mem_error_handler;
+
+void cil_set_mem_error_handler(void (*handler)(void))
+{
+ cil_mem_error_handler = handler;
+}
+
+void *cil_malloc(size_t size)
+{
+ void *mem = malloc(size);
+ if (mem == NULL){
+ if (size == 0) {
+ return NULL;
+ }
+ (*cil_mem_error_handler)();
+ }
+
+ return mem;
+}
+
+void *cil_calloc(size_t num_elements, size_t element_size)
+{
+ void *mem = calloc(num_elements, element_size);
+ if (mem == NULL){
+ (*cil_mem_error_handler)();
+ }
+
+ return mem;
+}
+
+void *cil_realloc(void *ptr, size_t size)
+{
+ void *mem = realloc(ptr, size);
+ if (mem == NULL){
+ if (size == 0) {
+ return NULL;
+ }
+ (*cil_mem_error_handler)();
+ }
+
+ return mem;
+}
+
+
+char *cil_strdup(const char *str)
+{
+ char *mem = NULL;
+
+ if (str == NULL) {
+ return NULL;
+ }
+
+ mem = strdup(str);
+ if (mem == NULL) {
+ (*cil_mem_error_handler)();
+ }
+
+ return mem;
+}
+
+__attribute__ ((format (printf, 2, 3))) int cil_asprintf(char **strp, const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = vasprintf(strp, fmt, ap);
+ va_end(ap);
+
+ if (rc == -1) {
+ (*cil_mem_error_handler)();
+ }
+
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_mem.h b/libsepol/cil/src/cil_mem.h
new file mode 100644
index 0000000..902ce13
--- /dev/null
+++ b/libsepol/cil/src/cil_mem.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_MEM_H_
+#define CIL_MEM_H_
+
+/* Wrapped malloc that catches errors and calls the error callback */
+void *cil_malloc(size_t size);
+void *cil_calloc(size_t num_elements, size_t element_size);
+void *cil_realloc(void *ptr, size_t size);
+char *cil_strdup(const char *str);
+int cil_asprintf(char **strp, const char *fmt, ...);
+void (*cil_mem_error_handler)(void);
+
+#endif /* CIL_MEM_H_ */
+
diff --git a/libsepol/cil/src/cil_parser.c b/libsepol/cil/src/cil_parser.c
new file mode 100644
index 0000000..101520c
--- /dev/null
+++ b/libsepol/cil/src/cil_parser.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_lexer.h"
+#include "cil_strpool.h"
+#include "cil_stack.h"
+
+char *CIL_KEY_HLL_LMS;
+char *CIL_KEY_HLL_LMX;
+char *CIL_KEY_HLL_LME;
+
+struct hll_info {
+ int hll_lineno;
+ int hll_expand;
+};
+
+static void push_hll_info(struct cil_stack *stack, int hll_lineno, int hll_expand)
+{
+ struct hll_info *new = cil_malloc(sizeof(*new));
+
+ new->hll_lineno = hll_lineno;
+ new->hll_expand = hll_expand;
+
+ cil_stack_push(stack, CIL_NONE, new);
+}
+
+static void pop_hll_info(struct cil_stack *stack, int *hll_lineno, int *hll_expand)
+{
+ struct cil_stack_item *curr = cil_stack_pop(stack);
+ struct cil_stack_item *prev = cil_stack_peek(stack);
+ struct hll_info *old;
+
+ free(curr->data);
+
+ if (!prev) {
+ *hll_lineno = -1;
+ *hll_expand = -1;
+ } else {
+ old = prev->data;
+ *hll_lineno = old->hll_lineno;
+ *hll_expand = old->hll_expand;
+ }
+}
+
+static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, int line, int hll_line, void *value)
+{
+ cil_tree_node_init(node);
+ (*node)->parent = current;
+ (*node)->flavor = CIL_NODE;
+ (*node)->line = line;
+ (*node)->hll_line = hll_line;
+ (*node)->data = value;
+}
+
+static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current)
+{
+ if (current->cl_head == NULL) {
+ current->cl_head = node;
+ } else {
+ current->cl_tail->next = node;
+ }
+ current->cl_tail = node;
+}
+
+static int add_hll_linemark(struct cil_tree_node **current, int *hll_lineno, int *hll_expand, struct cil_stack *stack, char *path)
+{
+ char *hll_type;
+ struct cil_tree_node *node;
+ struct token tok;
+ char *hll_file;
+ char *end = NULL;
+
+ cil_lexer_next(&tok);
+ hll_type = cil_strpool_add(tok.value);
+ if (hll_type == CIL_KEY_HLL_LME) {
+ if (cil_stack_is_empty(stack)) {
+ cil_log(CIL_ERR, "Line mark end without start\n");
+ goto exit;
+ }
+ pop_hll_info(stack, hll_lineno, hll_expand);
+ *current = (*current)->parent;
+ } else {
+ create_node(&node, *current, tok.line, *hll_lineno, NULL);
+ insert_node(node, *current);
+ *current = node;
+
+ create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_INFO);
+ insert_node(node, *current);
+
+ create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_HLL);
+ insert_node(node, *current);
+
+ if (hll_type == CIL_KEY_HLL_LMS) {
+ *hll_expand = 0;
+ } else if (hll_type == CIL_KEY_HLL_LMX) {
+ *hll_expand = 1;
+ } else {
+ cil_log(CIL_ERR, "Invalid line mark syntax\n");
+ goto exit;
+ }
+
+ cil_lexer_next(&tok);
+ if (tok.type != SYMBOL) {
+ cil_log(CIL_ERR, "Invalid line mark syntax\n");
+ goto exit;
+ }
+ *hll_lineno = strtol(tok.value, &end, 10);
+ if (errno == ERANGE || *end != '\0') {
+ cil_log(CIL_ERR, "Problem parsing line number for line mark\n");
+ goto exit;
+ }
+
+ push_hll_info(stack, *hll_lineno, *hll_expand);
+
+ cil_lexer_next(&tok);
+ if (tok.type != SYMBOL && tok.type != QSTRING) {
+ cil_log(CIL_ERR, "Invalid line mark syntax\n");
+ goto exit;
+ }
+
+ if (tok.type == QSTRING) {
+ tok.value[strlen(tok.value) - 1] = '\0';
+ tok.value = tok.value+1;
+ }
+
+ hll_file = cil_strpool_add(tok.value);
+
+ create_node(&node, *current, tok.line, *hll_lineno, hll_file);
+ insert_node(node, *current);
+ }
+
+ cil_lexer_next(&tok);
+ if (tok.type != NEWLINE) {
+ cil_log(CIL_ERR, "Invalid line mark syntax\n");
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Problem with high-level line mark at line %d of %s\n", tok.line, path);
+ return SEPOL_ERR;
+}
+
+static void add_cil_path(struct cil_tree_node **current, char *path)
+{
+ struct cil_tree_node *node;
+
+ create_node(&node, *current, 0, 0, NULL);
+ insert_node(node, *current);
+ *current = node;
+
+ create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO);
+ insert_node(node, *current);
+
+ create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL);
+ insert_node(node, *current);
+
+ create_node(&node, *current, 0, 0, path);
+ insert_node(node, *current);
+}
+
+int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree)
+{
+
+ int paren_count = 0;
+
+ struct cil_tree *tree = NULL;
+ struct cil_tree_node *node = NULL;
+ struct cil_tree_node *current = NULL;
+ char *path = cil_strpool_add(_path);
+ struct cil_stack *stack;
+ int hll_lineno = -1;
+ int hll_expand = -1;
+ struct token tok;
+ int rc = SEPOL_OK;
+
+ CIL_KEY_HLL_LMS = cil_strpool_add("lms");
+ CIL_KEY_HLL_LMX = cil_strpool_add("lmx");
+ CIL_KEY_HLL_LME = cil_strpool_add("lme");
+
+ cil_stack_init(&stack);
+
+ cil_lexer_setup(buffer, size);
+
+ tree = *parse_tree;
+ current = tree->root;
+
+ add_cil_path(¤t, path);
+
+ do {
+ cil_lexer_next(&tok);
+ switch (tok.type) {
+ case HLL_LINEMARK:
+ rc = add_hll_linemark(¤t, &hll_lineno, &hll_expand, stack, path);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ case OPAREN:
+ paren_count++;
+
+ create_node(&node, current, tok.line, hll_lineno, NULL);
+ insert_node(node, current);
+ current = node;
+ break;
+ case CPAREN:
+ paren_count--;
+ if (paren_count < 0) {
+ cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path);
+ goto exit;
+ }
+ current = current->parent;
+ break;
+ case QSTRING:
+ tok.value[strlen(tok.value) - 1] = '\0';
+ tok.value = tok.value+1;
+ case SYMBOL:
+ if (paren_count == 0) {
+ cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path);
+ goto exit;
+ }
+
+ create_node(&node, current, tok.line, hll_lineno, cil_strpool_add(tok.value));
+ insert_node(node, current);
+ break;
+ case NEWLINE :
+ if (!hll_expand) {
+ hll_lineno++;
+ }
+ break;
+ case COMMENT:
+ while (tok.type != NEWLINE && tok.type != END_OF_FILE) {
+ cil_lexer_next(&tok);
+ }
+ if (!hll_expand) {
+ hll_lineno++;
+ }
+ if (tok.type != END_OF_FILE) {
+ break;
+ }
+ // Fall through if EOF
+ case END_OF_FILE:
+ if (paren_count > 0) {
+ cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path);
+ goto exit;
+ }
+ if (!cil_stack_is_empty(stack)) {
+ cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path);
+ goto exit;
+ }
+ break;
+ case UNKNOWN:
+ cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path);
+ goto exit;
+ default:
+ cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path);
+ goto exit;
+ }
+ }
+ while (tok.type != END_OF_FILE);
+
+ cil_lexer_destroy();
+
+ cil_stack_destroy(&stack);
+
+ *parse_tree = tree;
+
+ return SEPOL_OK;
+
+exit:
+ while (!cil_stack_is_empty(stack)) {
+ pop_hll_info(stack, &hll_lineno, &hll_expand);
+ }
+ cil_stack_destroy(&stack);
+
+ return SEPOL_ERR;
+}
diff --git a/libsepol/cil/src/cil_parser.h b/libsepol/cil/src/cil_parser.h
new file mode 100644
index 0000000..02ecb78
--- /dev/null
+++ b/libsepol/cil/src/cil_parser.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_PARSER_H_
+#define CIL_PARSER_H_
+
+#include "cil_tree.h"
+
+int cil_parser(char *path, char *buffer, uint32_t size, struct cil_tree **parse_tree);
+
+#endif /* CIL_PARSER_H_ */
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
new file mode 100644
index 0000000..382129b
--- /dev/null
+++ b/libsepol/cil/src/cil_policy.c
@@ -0,0 +1,1426 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sepol/policydb/conditional.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_policy.h"
+#include "cil_symtab.h"
+#include "cil_strpool.h"
+
+#define SEPOL_DONE 555
+
+#define CLASS_DECL 0
+#define ISIDS 1
+#define COMMONS 2
+#define CLASSES 3
+#define INTERFACES 4
+#define SENS 5
+#define CATS 6
+#define LEVELS 7
+#define CONSTRAINS 8
+#define TYPEATTRTYPES 9
+#define ALIASES 10
+#define ALLOWS 11
+#define CONDS 12
+#define USERROLES 13
+#define SIDS 14
+#define NETIFCONS 15
+
+#define BUFFER 1024
+#define NUM_POLICY_FILES 16
+
+struct cil_args_genpolicy {
+ struct cil_list *users;
+ struct cil_list *sens;
+ struct cil_list *cats;
+ FILE **file_arr;
+};
+
+struct cil_args_booleanif {
+ FILE **file_arr;
+ uint32_t *file_index;
+};
+
+
+int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
+
+int cil_combine_policy(FILE **file_arr, FILE *policy_file)
+{
+ char temp[BUFFER];
+ int i, rc, rc_read, rc_write;
+
+ for(i=0; i<NUM_POLICY_FILES; i++) {
+ fseek(file_arr[i], 0, SEEK_SET);
+ while (!feof(file_arr[i])) {
+ rc_read = fread(temp, 1, BUFFER, file_arr[i]);
+ if (rc_read == 0 && ferror(file_arr[i])) {
+ cil_log(CIL_ERR, "Error reading temp policy file\n");
+ return SEPOL_ERR;
+ }
+ rc_write = 0;
+ while (rc_read > rc_write) {
+ rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file);
+ rc_write += rc;
+ if (rc == 0 && ferror(file_arr[i])) {
+ cil_log(CIL_ERR, "Error writing to policy.conf\n");
+ return SEPOL_ERR;
+ }
+ }
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i=0; i<sort->count; i++) {
+ struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "portcon ");
+ if (portcon->proto == CIL_PROTOCOL_UDP) {
+ fprintf(file_arr[NETIFCONS], "udp ");
+ } else if (portcon->proto == CIL_PROTOCOL_TCP) {
+ fprintf(file_arr[NETIFCONS], "tcp ");
+ } else if (portcon->proto == CIL_PROTOCOL_DCCP) {
+ fprintf(file_arr[NETIFCONS], "dccp ");
+ }
+ fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low);
+ fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high);
+ cil_context_to_policy(file_arr, NETIFCONS, portcon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i=0; i<sort->count; i++) {
+ struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str);
+ fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str);
+ cil_context_to_policy(file_arr, NETIFCONS, genfscon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i=0; i<sort->count; i++) {
+ struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str);
+ cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context);
+ fprintf(file_arr[NETIFCONS], " ");
+ cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+ int rc = SEPOL_ERR;
+
+ for (i=0; i<sort->count; i++) {
+ struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i];
+ char *buf = NULL;
+ errno = 0;
+ if (nodecon->addr->family == AF_INET) {
+ buf = cil_malloc(INET_ADDRSTRLEN);
+ inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN);
+ } else if (nodecon->addr->family == AF_INET6) {
+ buf = cil_malloc(INET6_ADDRSTRLEN);
+ inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN);
+ }
+
+ if (errno != 0) {
+ cil_log(CIL_INFO, "Failed to convert ip address to string\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ fprintf(file_arr[NETIFCONS], "nodecon %s ", buf);
+ free(buf);
+
+ if (nodecon->mask->family == AF_INET) {
+ buf = cil_malloc(INET_ADDRSTRLEN);
+ inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN);
+ } else if (nodecon->mask->family == AF_INET6) {
+ buf = cil_malloc(INET6_ADDRSTRLEN);
+ inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN);
+ }
+
+ if (errno != 0) {
+ cil_log(CIL_INFO, "Failed to convert mask to string\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ fprintf(file_arr[NETIFCONS], "%s ", buf);
+ free(buf);
+
+ cil_context_to_policy(file_arr, NETIFCONS, nodecon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < sort->count; i++) {
+ struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq);
+ cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < sort->count; i++) {
+ struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high);
+ cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < sort->count; i++) {
+ struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
+ cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < sort->count; i++) {
+ struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i];
+ fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev);
+ cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort)
+{
+ uint32_t i = 0;
+
+ for (i=0; i<sort->count; i++) {
+ struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i];
+ if (fsuse->type == CIL_FSUSE_XATTR) {
+ fprintf(file_arr[NETIFCONS], "fs_use_xattr ");
+ } else if (fsuse->type == CIL_FSUSE_TASK) {
+ fprintf(file_arr[NETIFCONS], "fs_use_task ");
+ } else if (fsuse->type == CIL_FSUSE_TRANS) {
+ fprintf(file_arr[NETIFCONS], "fs_use_trans ");
+ } else {
+ return SEPOL_ERR;
+ }
+ fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str);
+ cil_context_to_policy(file_arr, NETIFCONS, fsuse->context);
+ fprintf(file_arr[NETIFCONS], ";\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor)
+{
+ struct cil_list_item *curr_key;
+ struct cil_multimap_item *new_data;
+
+ if (list == NULL || key == NULL) {
+ return SEPOL_ERR;
+ }
+
+ cil_list_for_each(curr_key, list) {
+ struct cil_multimap_item *curr_multimap_item = curr_key->data;
+ if (curr_multimap_item != NULL) {
+ if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) {
+ struct cil_list_item *curr_value;
+ cil_list_for_each(curr_value, curr_multimap_item->values) {
+ if (curr_value == (struct cil_list_item*)value) {
+ return SEPOL_OK;;
+ }
+ }
+ cil_list_append(curr_multimap_item->values, val_flavor, value);
+ }
+ } else {
+ cil_log(CIL_INFO, "No data in list item\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ new_data = cil_malloc(sizeof(*new_data));
+ new_data->key = key;
+ cil_list_init(&new_data->values, CIL_LIST_ITEM);
+ if (value != NULL) {
+ cil_list_append(new_data->values, val_flavor, value);
+ }
+ cil_list_append(list, key_flavor, new_data);
+
+ return SEPOL_OK;
+}
+
+int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles)
+{
+ struct cil_list_item *current_user;
+
+ if (userroles == NULL) {
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(current_user, userroles) {
+ struct cil_multimap_item *user_multimap_item = current_user->data;
+ struct cil_list_item *current_role;
+ if (user_multimap_item->values->head == NULL) {
+ cil_log(CIL_INFO, "No roles associated with user %s\n",
+ user_multimap_item->key->name);
+ return SEPOL_ERR;
+ }
+
+ fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name);
+
+ cil_list_for_each(current_role, user_multimap_item->values) {
+ fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name);
+ }
+ fprintf(file_arr[USERROLES], " };\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats)
+{
+ struct cil_list_item *curr_cat;
+
+ if (cats == NULL) {
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(curr_cat, cats) {
+ struct cil_multimap_item *cat_multimap_item = curr_cat->data;
+ fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name);
+ if (cat_multimap_item->values->head == NULL) {
+ fprintf(file_arr[CATS], ";\n");
+ } else {
+ struct cil_list_item *curr_catalias;
+ fprintf(file_arr[CATS], " alias");
+ cil_list_for_each(curr_catalias, cat_multimap_item->values) {
+ fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name);
+ }
+ fprintf(file_arr[CATS], ";\n");
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens)
+{
+ struct cil_list_item *curr_sens;
+
+ if (sens == NULL) {
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(curr_sens, sens) {
+ struct cil_multimap_item *sens_multimap_item = curr_sens->data;
+ fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name);
+ if (sens_multimap_item->values->head == NULL)
+ fprintf(file_arr[SENS], ";\n");
+ else {
+ struct cil_list_item *curr_sensalias;
+ fprintf(file_arr[SENS], " alias");
+ cil_list_for_each(curr_sensalias, sens_multimap_item->values) {
+ fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name);
+ }
+ fprintf(file_arr[SENS], ";\n");
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats)
+{
+ cil_expr_to_policy(file_arr, file_index, cats->datum_expr);
+}
+
+void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level)
+{
+ char *sens_str = level->sens->datum.name;
+
+ fprintf(file_arr[file_index], "%s", sens_str);
+ if (level->cats != NULL) {
+ fprintf(file_arr[file_index], ":");
+ cil_cats_to_policy(file_arr, file_index, level->cats);
+ }
+}
+
+void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange)
+{
+ struct cil_level *low = lvlrange->low;
+ struct cil_level *high = lvlrange->high;
+
+ cil_level_to_policy(file_arr, file_index, low);
+ fprintf(file_arr[file_index], "-");
+ cil_level_to_policy(file_arr, file_index, high);
+}
+
+void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context)
+{
+ char *user_str = ((struct cil_symtab_datum*)context->user)->name;
+ char *role_str = ((struct cil_symtab_datum*)context->role)->name;
+ char *type_str = ((struct cil_symtab_datum*)context->type)->name;
+ struct cil_levelrange *lvlrange = context->range;
+
+ fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str);
+ cil_levelrange_to_policy(file_arr, file_index, lvlrange);
+}
+
+void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list)
+{
+ struct cil_list_item *curr;
+
+ fprintf(file_arr[file_index], " {");
+ cil_list_for_each(curr, list) {
+ switch (curr->flavor) {
+ case CIL_LIST:
+ cil_perms_to_policy(file_arr, file_index, curr->data);
+ break;
+ case CIL_STRING:
+ fprintf(file_arr[file_index], " %s", (char *)curr->data);
+ break;
+ case CIL_DATUM:
+ fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name);
+ break;
+ case CIL_OP: {
+ enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+ char *op_str = NULL;
+
+ switch (op_flavor) {
+ case CIL_AND:
+ op_str = CIL_KEY_AND;
+ break;
+ case CIL_OR:
+ op_str = CIL_KEY_OR;
+ break;
+ case CIL_NOT:
+ op_str = CIL_KEY_NOT;
+ break;
+ case CIL_ALL:
+ op_str = CIL_KEY_ALL;
+ break;
+ case CIL_XOR:
+ op_str = CIL_KEY_XOR;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown operator in expression\n");
+ break;
+ }
+ fprintf(file_arr[file_index], " %s", op_str);
+ break;
+ }
+ default:
+ cil_log(CIL_ERR, "Unknown flavor in expression\n");
+ break;
+ }
+ }
+ fprintf(file_arr[file_index], " }");
+}
+
+void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr)
+{
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name);
+ cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms);
+ fprintf(file_arr[CONSTRAINS], "\n\t");
+ cil_expr_to_policy(file_arr, CONSTRAINS, expr);
+ fprintf(file_arr[CONSTRAINS], ";\n");
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr);
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr);
+ }
+ }
+}
+
+void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor)
+{
+ char *kind = NULL;
+
+ if (flavor == CIL_CONSTRAIN) {
+ kind = CIL_KEY_CONSTRAIN;
+ } else if (flavor == CIL_MLSCONSTRAIN) {
+ kind = CIL_KEY_MLSCONSTRAIN;
+ }
+
+ cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr);
+}
+
+void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms)
+{
+ struct cil_list_item *i;
+
+ cil_list_for_each(i, classperms) {
+ if (i->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = i->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name);
+ cil_perms_to_policy(file_arr, file_index, cp->perms);
+ fprintf(file_arr[file_index], ";\n");
+ } else { /* MAP */
+ struct cil_list_item *j = NULL;
+ cil_list_for_each(j, cp->perms) {
+ struct cil_perm *cmp = j->data;
+ cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms);
+ }
+ }
+ } else { /* SET */
+ struct cil_list_item *j;
+ struct cil_classperms_set *cp_set = i->data;
+ struct cil_classpermission *cp = cp_set->set;
+ cil_list_for_each(j, cp->classperms) {
+ cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data);
+ }
+ }
+ }
+}
+
+int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule)
+{
+ const char *kind_str = NULL;
+ const char *src_str = DATUM(rule->src)->name;
+ const char *tgt_str = DATUM(rule->tgt)->name;
+
+
+ switch (rule->rule_kind) {
+ case CIL_AVRULE_ALLOWED:
+ kind_str = "allow";
+ break;
+ case CIL_AVRULE_AUDITALLOW:
+ kind_str = "auditallow";
+ break;
+ case CIL_AVRULE_DONTAUDIT:
+ kind_str = "dontaudit";
+ break;
+ case CIL_AVRULE_NEVERALLOW:
+ kind_str = "neverallow";
+ break;
+ default :
+ cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n",
+ rule->rule_kind, src_str, tgt_str);
+ return SEPOL_ERR;
+ }
+
+ cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->perms.classperms);
+
+ return SEPOL_OK;
+}
+
+int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule)
+{
+ char *src_str = ((struct cil_symtab_datum*)rule->src)->name;
+ char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name;
+ char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name;
+ char *result_str = ((struct cil_symtab_datum*)rule->result)->name;
+
+ switch (rule->rule_kind) {
+ case CIL_TYPE_TRANSITION:
+ fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
+ break;
+ case CIL_TYPE_CHANGE:
+ fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str);
+ break;
+ case CIL_TYPE_MEMBER:
+ fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
+ break;
+ default:
+ cil_log(CIL_INFO, "Unknown type_rule\n");
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans)
+{
+ char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name;
+ char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name;
+ char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name;
+ char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name;
+
+ fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str);
+ return SEPOL_OK;
+}
+
+static int cil_expr_to_string(struct cil_list *expr, char **out)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ char *stack[COND_EXPR_MAXDEPTH] = {};
+ int pos = 0;
+ int i;
+
+ cil_list_for_each(curr, expr) {
+ if (pos > COND_EXPR_MAXDEPTH) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ switch (curr->flavor) {
+ case CIL_LIST:
+ rc = cil_expr_to_string(curr->data, &stack[pos]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ pos++;
+ break;
+ case CIL_STRING:
+ stack[pos] = curr->data;
+ pos++;
+ break;
+ case CIL_DATUM:
+ stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
+ pos++;
+ break;
+ case CIL_OP: {
+ int len;
+ char *expr_str;
+ enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+ char *op_str = NULL;
+
+ if (pos == 0) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ switch (op_flavor) {
+ case CIL_AND:
+ op_str = CIL_KEY_AND;
+ break;
+ case CIL_OR:
+ op_str = CIL_KEY_OR;
+ break;
+ case CIL_NOT:
+ op_str = CIL_KEY_NOT;
+ break;
+ case CIL_ALL:
+ op_str = CIL_KEY_ALL;
+ break;
+ case CIL_EQ:
+ op_str = CIL_KEY_EQ;
+ break;
+ case CIL_NEQ:
+ op_str = CIL_KEY_NEQ;
+ break;
+ case CIL_XOR:
+ op_str = CIL_KEY_XOR;
+ break;
+ case CIL_CONS_DOM:
+ op_str = CIL_KEY_CONS_DOM;
+ break;
+ case CIL_CONS_DOMBY:
+ op_str = CIL_KEY_CONS_DOMBY;
+ break;
+ case CIL_CONS_INCOMP:
+ op_str = CIL_KEY_CONS_INCOMP;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown operator in expression\n");
+ goto exit;
+ break;
+ }
+ if (op_flavor == CIL_NOT) {
+ len = strlen(stack[pos-1]) + strlen(op_str) + 4;
+ expr_str = cil_malloc(len);
+ snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
+ free(stack[pos-1]);
+ stack[pos-1] = NULL;
+ pos--;
+ } else {
+ if (pos < 2) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
+ expr_str = cil_malloc(len);
+ snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]);
+ free(stack[pos-2]);
+ free(stack[pos-1]);
+ stack[pos-2] = NULL;
+ stack[pos-1] = NULL;
+ pos -= 2;
+ }
+ stack[pos] = expr_str;
+ pos++;
+ break;
+ }
+ case CIL_CONS_OPERAND: {
+ enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
+ char *operand_str = NULL;
+ switch (operand_flavor) {
+ case CIL_CONS_U1:
+ operand_str = CIL_KEY_CONS_U1;
+ break;
+ case CIL_CONS_U2:
+ operand_str = CIL_KEY_CONS_U2;
+ break;
+ case CIL_CONS_U3:
+ operand_str = CIL_KEY_CONS_U3;
+ break;
+ case CIL_CONS_T1:
+ operand_str = CIL_KEY_CONS_T1;
+ break;
+ case CIL_CONS_T2:
+ operand_str = CIL_KEY_CONS_T2;
+ break;
+ case CIL_CONS_T3:
+ operand_str = CIL_KEY_CONS_T3;
+ break;
+ case CIL_CONS_R1:
+ operand_str = CIL_KEY_CONS_R1;
+ break;
+ case CIL_CONS_R2:
+ operand_str = CIL_KEY_CONS_R2;
+ break;
+ case CIL_CONS_R3:
+ operand_str = CIL_KEY_CONS_R3;
+ break;
+ case CIL_CONS_L1:
+ operand_str = CIL_KEY_CONS_L1;
+ break;
+ case CIL_CONS_L2:
+ operand_str = CIL_KEY_CONS_L2;
+ break;
+ case CIL_CONS_H1:
+ operand_str = CIL_KEY_CONS_H1;
+ break;
+ case CIL_CONS_H2:
+ operand_str = CIL_KEY_CONS_H2;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown operand in expression\n");
+ goto exit;
+ break;
+ }
+ stack[pos] = operand_str;
+ pos++;
+ break;
+ }
+ default:
+ cil_log(CIL_ERR, "Unknown flavor in expression\n");
+ goto exit;
+ break;
+ }
+ }
+
+ *out = stack[0];
+
+ return SEPOL_OK;
+
+exit:
+ for (i = 0; i < pos; i++) {
+ free(stack[i]);
+ }
+ return rc;
+}
+
+int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr)
+{
+ int rc = SEPOL_ERR;
+ char *str_out;
+
+ rc = cil_expr_to_string(expr, &str_out);
+ if (rc != SEPOL_OK) {
+ goto out;
+ }
+ fprintf(file_arr[file_index], "%s", str_out);
+ free(str_out);
+
+ return SEPOL_OK;
+
+out:
+ return rc;
+}
+
+int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_booleanif *args;
+ FILE **file_arr;
+ uint32_t *file_index;
+
+ args = extra_args;
+ file_arr = args->file_arr;
+ file_index = args->file_index;
+
+ switch (node->flavor) {
+ case CIL_AVRULE:
+ rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc);
+ return rc;
+ }
+ break;
+ case CIL_TYPE_RULE:
+ rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc);
+ return rc;
+ }
+ break;
+ case CIL_FALSE:
+ fprintf(file_arr[*file_index], "else {\n");
+ break;
+ case CIL_TRUE:
+ break;
+ default:
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args)
+{
+ struct cil_args_booleanif *args;
+ FILE **file_arr;
+ uint32_t *file_index;
+
+ args = extra_args;
+ file_arr = args->file_arr;
+ file_index = args->file_index;
+
+ if (node->parent->flavor == CIL_FALSE) {
+ fprintf(file_arr[*file_index], "}\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_booleanif *bif = node->data;
+ struct cil_list *expr = bif->datum_expr;
+ struct cil_args_booleanif extra_args;
+ struct cil_tree_node *true_node = NULL;
+ struct cil_tree_node *false_node = NULL;
+ struct cil_condblock *cb = NULL;
+
+ extra_args.file_arr = file_arr;
+ extra_args.file_index = &file_index;;
+
+ fprintf(file_arr[file_index], "if ");
+
+ rc = cil_expr_to_policy(file_arr, file_index, expr);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to write expression\n");
+ return rc;
+ }
+
+ if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) {
+ cb = node->cl_head->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ true_node = node->cl_head;
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ false_node = node->cl_head;
+ }
+ }
+
+ if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) {
+ cb = node->cl_head->next->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ true_node = node->cl_head->next;
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ false_node = node->cl_head->next;
+ }
+ }
+
+ fprintf(file_arr[file_index], "{\n");
+ if (true_node != NULL) {
+ rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc);
+ return rc;
+ }
+ }
+ fprintf(file_arr[file_index], "}\n");
+
+ if (false_node != NULL) {
+ fprintf(file_arr[file_index], "else {\n");
+ rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc);
+ return rc;
+ }
+ fprintf(file_arr[file_index], "}\n");
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current)
+{
+ uint32_t flavor = current->flavor;
+ int rc = SEPOL_ERR;
+
+ switch(flavor) {
+ case CIL_TYPEATTRIBUTE:
+ fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ case CIL_TYPE:
+ fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ case CIL_TYPEALIAS: {
+ struct cil_alias *alias = current->data;
+ fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ }
+ case CIL_TYPEBOUNDS: {
+ struct cil_bounds *bnds = current->data;
+ fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str);
+ break;
+ }
+ case CIL_TYPEPERMISSIVE: {
+ struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data;
+ fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name);
+ break;
+ }
+ case CIL_ROLE:
+ fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ case CIL_BOOL: {
+ const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false";
+ fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean);
+ break;
+ }
+ case CIL_COMMON:
+ fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name);
+
+ if (current->cl_head != NULL) {
+ current = current->cl_head;
+ fprintf(file_arr[COMMONS], " {");
+ } else {
+ cil_log(CIL_INFO, "No permissions given\n");
+ return SEPOL_ERR;
+ }
+
+ while (current != NULL) {
+ if (current->flavor == CIL_PERM) {
+ fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name);
+ } else {
+ cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor);
+ return SEPOL_ERR;
+ }
+ current = current->next;
+ }
+ fprintf(file_arr[COMMONS], "}\n");
+
+ return SEPOL_DONE;
+ case CIL_AVRULE: {
+ struct cil_avrule *avrule = (struct cil_avrule*)current->data;
+ rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write avrule to policy\n");
+ return rc;
+ }
+ break;
+ }
+ case CIL_TYPE_RULE: {
+ struct cil_type_rule *rule = (struct cil_type_rule*)current->data;
+ rc = cil_typerule_to_policy(file_arr, ALLOWS, rule);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write type rule to policy\n");
+ return rc;
+ }
+ break;
+ }
+ case CIL_NAMETYPETRANSITION: {
+ struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data;
+ rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n");
+ return rc;
+ }
+ }
+ case CIL_ROLETRANSITION: {
+ struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data;
+ char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name;
+ char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name;
+ char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name;
+ char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name;
+
+ fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str);
+ break;
+ }
+ case CIL_ROLEALLOW: {
+ struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data;
+ char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name;
+ char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name;
+
+ fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str);
+ break;
+ }
+ case CIL_ROLETYPE: {
+ struct cil_roletype *roletype = (struct cil_roletype*)current->data;
+ char *role_str = ((struct cil_symtab_datum*)roletype->role)->name;
+ char *type_str = ((struct cil_symtab_datum*)roletype->type)->name;
+
+ fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str);
+ break;
+ }
+ case CIL_LEVEL:
+ fprintf(file_arr[LEVELS], "level ");
+ cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data);
+ fprintf(file_arr[LEVELS], ";\n");
+ break;
+ case CIL_CONSTRAIN:
+ cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
+ break;
+ case CIL_MLSCONSTRAIN:
+ cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
+ break;
+ case CIL_VALIDATETRANS: {
+ struct cil_validatetrans *vt = current->data;
+ fprintf(file_arr[CONSTRAINS], "validatetrans");
+ fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name);
+ cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
+ fprintf(file_arr[CONSTRAINS], ";\n");
+ break;
+ }
+ case CIL_MLSVALIDATETRANS: {
+ struct cil_validatetrans *vt = current->data;
+ fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans");
+ fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name);
+ cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
+ fprintf(file_arr[CONSTRAINS], ";\n");
+ break;
+ }
+ case CIL_SID:
+ fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ case CIL_SIDCONTEXT: {
+ struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data;
+ fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str);
+ cil_context_to_policy(file_arr, SIDS, sidcon->context);
+ fprintf(file_arr[SIDS], "\n");
+ break;
+ }
+ case CIL_POLICYCAP:
+ fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name);
+ break;
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_genpolicy *args = NULL;
+ struct cil_list *users = NULL;
+ struct cil_list *sens = NULL;
+ struct cil_list *cats = NULL;
+ FILE **file_arr = NULL;
+
+ if (extra_args == NULL) {
+ return SEPOL_ERR;
+ }
+
+ *finished = CIL_TREE_SKIP_NOTHING;
+
+ args = extra_args;
+ users = args->users;
+ sens = args->sens;
+ cats = args->cats;
+ file_arr = args->file_arr;
+
+ if (node->cl_head != NULL) {
+ if (node->flavor == CIL_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ return SEPOL_OK;
+ }
+
+ if (node->flavor == CIL_BOOLEANIF) {
+ rc = cil_booleanif_to_policy(file_arr, CONDS, node);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to write booleanif contents to file\n");
+ return rc;
+ }
+ *finished = CIL_TREE_SKIP_HEAD;
+ return SEPOL_OK;
+ }
+
+ if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ return SEPOL_OK;
+ }
+
+ if (node->flavor != CIL_ROOT) {
+ rc = cil_name_to_policy(file_arr, node);
+ if (rc != SEPOL_OK && rc != SEPOL_DONE) {
+ cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor);
+ return SEPOL_ERR;
+ }
+ }
+ } else {
+ switch (node->flavor) {
+ case CIL_USER:
+ cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
+ break;
+ case CIL_CATALIAS: {
+ struct cil_alias *alias = node->data;
+ struct cil_symtab_datum *datum = alias->actual;
+ cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
+ }
+ break;
+ case CIL_SENSALIAS: {
+ struct cil_alias *alias = node->data;
+ struct cil_symtab_datum *datum = alias->actual;
+ cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
+ }
+ break;
+ default:
+ rc = cil_name_to_policy(file_arr, node);
+ if (rc != SEPOL_OK && rc != SEPOL_DONE) {
+ cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
+ return SEPOL_ERR;
+ }
+ break;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_gen_policy(struct cil_db *db)
+{
+ struct cil_tree_node *curr = db->ast->root;
+ struct cil_list_item *item;
+ int rc = SEPOL_ERR;
+ FILE *policy_file;
+ FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
+ char *file_path_arr[NUM_POLICY_FILES];
+ char temp[32];
+
+ struct cil_list *users = NULL;
+ struct cil_list *cats = NULL;
+ struct cil_list *sens = NULL;
+ struct cil_args_genpolicy extra_args;
+
+ cil_list_init(&users, CIL_LIST_ITEM);
+ cil_list_init(&cats, CIL_LIST_ITEM);
+ cil_list_init(&sens, CIL_LIST_ITEM);
+
+ strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
+ file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_isids-XXXXXX");
+ file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[ISIDS] = cil_strpool_add(temp);
+
+ strcpy(temp,"/tmp/cil_common-XXXXXX");
+ file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[COMMONS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_class-XXXXXX");
+ file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[CLASSES] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_interf-XXXXXX");
+ file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[INTERFACES] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_sens-XXXXXX");
+ file_arr[SENS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[SENS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_cats-XXXXXX");
+ file_arr[CATS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[CATS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_levels-XXXXXX");
+ file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[LEVELS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
+ file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
+ file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_aliases-XXXXXX");
+ file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[ALIASES] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_allows-XXXXXX");
+ file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[ALLOWS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_conds-XXXXXX");
+ file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[CONDS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_userroles-XXXXXX");
+ file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[USERROLES] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_sids-XXXXXX");
+ file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[SIDS] = cil_strpool_add(temp);
+
+ strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
+ file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
+ file_path_arr[NETIFCONS] = cil_strpool_add(temp);
+
+ policy_file = fopen("policy.conf", "w+");
+
+ cil_list_for_each(item, db->sidorder) {
+ fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
+ }
+
+ cil_list_for_each(item, db->classorder) {
+ struct cil_class *class = item->data;
+ struct cil_tree_node *node = class->datum.nodes->head->data;
+
+ fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
+
+ fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
+ if (class->common != NULL) {
+ fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
+ }
+ if (node->cl_head != NULL) {
+ struct cil_tree_node *curr_perm = node->cl_head;
+ fprintf(file_arr[CLASSES], "{ ");
+ while (curr_perm != NULL) {
+ fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
+ curr_perm = curr_perm->next;
+ }
+ fprintf(file_arr[CLASSES], "}");
+ }
+ fprintf(file_arr[CLASSES], "\n");
+ }
+
+ if (db->catorder->head != NULL) {
+ cil_list_for_each(item, db->catorder) {
+ cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
+ }
+ }
+
+ if (db->sensitivityorder->head != NULL) {
+ fprintf(file_arr[SENS], "sensitivityorder { ");
+ cil_list_for_each(item, db->sensitivityorder) {
+ fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
+ }
+ fprintf(file_arr[SENS], "};\n");
+ }
+
+ extra_args.users = users;
+ extra_args.sens = sens;
+ extra_args.cats = cats;
+ extra_args.file_arr= file_arr;
+
+ rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error walking tree\n");
+ return rc;
+ }
+
+ rc = cil_netifcon_to_policy(file_arr, db->netifcon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_genfscon_to_policy(file_arr, db->genfscon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_portcon_to_policy(file_arr, db->portcon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_nodecon_to_policy(file_arr, db->nodecon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_fsuse_to_policy(file_arr, db->fsuse);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return rc;
+ }
+
+ rc = cil_userrole_to_policy(file_arr, users);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return SEPOL_ERR;
+ }
+
+ rc = cil_sens_to_policy(file_arr, sens);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return SEPOL_ERR;
+ }
+
+ rc = cil_cat_to_policy(file_arr, cats);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return SEPOL_ERR;
+ }
+
+ rc = cil_combine_policy(file_arr, policy_file);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Error creating policy.conf\n");
+ return SEPOL_ERR;
+ }
+
+ // Remove temp files
+ int i;
+ for (i=0; i<NUM_POLICY_FILES; i++) {
+ rc = fclose(file_arr[i]);
+ if (rc != 0) {
+ cil_log(CIL_ERR, "Error closing temporary file\n");
+ return SEPOL_ERR;
+ }
+ rc = unlink(file_path_arr[i]);
+ if (rc != 0) {
+ cil_log(CIL_ERR, "Error unlinking temporary files\n");
+ return SEPOL_ERR;
+ }
+ }
+
+ rc = fclose(policy_file);
+ if (rc != 0) {
+ cil_log(CIL_ERR, "Error closing policy.conf\n");
+ return SEPOL_ERR;
+ }
+ free(file_arr);
+
+ cil_list_destroy(&users, CIL_FALSE);
+ cil_list_destroy(&cats, CIL_FALSE);
+ cil_list_destroy(&sens, CIL_FALSE);
+
+ return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_policy.h b/libsepol/cil/src/cil_policy.h
new file mode 100644
index 0000000..72cf162
--- /dev/null
+++ b/libsepol/cil/src/cil_policy.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_POLICY_H_
+#define CIL_POLICY_H_
+
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_internal.h"
+
+struct cil_multimap_item {
+ struct cil_symtab_datum *key;
+ struct cil_list *values;
+};
+
+int cil_combine_policy(FILE **file_arr, FILE *policy_file);
+void cil_context_to_policy(FILE **, uint32_t, struct cil_context *);
+int cil_name_to_policy(FILE **, struct cil_tree_node *);
+int cil_gen_policy(struct cil_db *);
+
+#endif
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
new file mode 100644
index 0000000..a694b33
--- /dev/null
+++ b/libsepol/cil/src/cil_post.c
@@ -0,0 +1,2056 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sepol/policydb/conditional.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_post.h"
+#include "cil_policy.h"
+#include "cil_verify.h"
+#include "cil_symtab.h"
+
+static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
+static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
+
+static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
+{
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, list) {
+ switch (curr->flavor) {
+ case CIL_LIST:
+ return CIL_FALSE;
+ break;
+ case CIL_OP:
+ return CIL_FALSE;
+ break;
+ default:
+ if (flavor == CIL_CAT) {
+ struct cil_symtab_datum *d = curr->data;
+ struct cil_tree_node *n = d->nodes->head->data;
+ if (n->flavor == CIL_CATSET) {
+ return CIL_FALSE;
+ }
+ }
+ break;
+ }
+ }
+ return CIL_TRUE;
+}
+
+void cil_post_fc_fill_data(struct fc_data *fc, char *path)
+{
+ int c = 0;
+ fc->meta = 0;
+ fc->stem_len = 0;
+ fc->str_len = 0;
+
+ while (path[c] != '\0') {
+ switch (path[c]) {
+ case '.':
+ case '^':
+ case '$':
+ case '?':
+ case '*':
+ case '+':
+ case '|':
+ case '[':
+ case '(':
+ case '{':
+ fc->meta = 1;
+ break;
+ case '\\':
+ c++;
+ default:
+ if (!fc->meta) {
+ fc->stem_len++;
+ }
+ break;
+ }
+ fc->str_len++;
+ c++;
+ }
+}
+
+int cil_post_filecon_compare(const void *a, const void *b)
+{
+ int rc = 0;
+ struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
+ struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
+ struct fc_data *a_data = cil_malloc(sizeof(*a_data));
+ struct fc_data *b_data = cil_malloc(sizeof(*b_data));
+ char *a_path = cil_malloc(strlen(a_filecon->path_str) + 1);
+ a_path[0] = '\0';
+ char *b_path = cil_malloc(strlen(b_filecon->path_str) + 1);
+ b_path[0] = '\0';
+ strcat(a_path, a_filecon->path_str);
+ strcat(b_path, b_filecon->path_str);
+ cil_post_fc_fill_data(a_data, a_path);
+ cil_post_fc_fill_data(b_data, b_path);
+ if (a_data->meta && !b_data->meta) {
+ rc = -1;
+ } else if (b_data->meta && !a_data->meta) {
+ rc = 1;
+ } else if (a_data->stem_len < b_data->stem_len) {
+ rc = -1;
+ } else if (b_data->stem_len < a_data->stem_len) {
+ rc = 1;
+ } else if (a_data->str_len < b_data->str_len) {
+ rc = -1;
+ } else if (b_data->str_len < a_data->str_len) {
+ rc = 1;
+ } else if (a_filecon->type < b_filecon->type) {
+ rc = -1;
+ } else if (b_filecon->type < a_filecon->type) {
+ rc = 1;
+ }
+
+ free(a_path);
+ free(b_path);
+ free(a_data);
+ free(b_data);
+
+ return rc;
+}
+
+int cil_post_portcon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_portcon *aportcon = *(struct cil_portcon**)a;
+ struct cil_portcon *bportcon = *(struct cil_portcon**)b;
+
+ rc = (aportcon->port_high - aportcon->port_low)
+ - (bportcon->port_high - bportcon->port_low);
+ if (rc == 0) {
+ if (aportcon->port_low < bportcon->port_low) {
+ rc = -1;
+ } else if (bportcon->port_low < aportcon->port_low) {
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
+
+int cil_post_genfscon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_genfscon *agenfscon = *(struct cil_genfscon**)a;
+ struct cil_genfscon *bgenfscon = *(struct cil_genfscon**)b;
+
+ rc = strcmp(agenfscon->fs_str, bgenfscon->fs_str);
+ if (rc == 0) {
+ rc = strcmp(agenfscon->path_str, bgenfscon->path_str);
+ }
+
+ return rc;
+}
+
+int cil_post_netifcon_compare(const void *a, const void *b)
+{
+ struct cil_netifcon *anetifcon = *(struct cil_netifcon**)a;
+ struct cil_netifcon *bnetifcon = *(struct cil_netifcon**)b;
+
+ return strcmp(anetifcon->interface_str, bnetifcon->interface_str);
+}
+
+int cil_post_nodecon_compare(const void *a, const void *b)
+{
+ struct cil_nodecon *anodecon;
+ struct cil_nodecon *bnodecon;
+ anodecon = *(struct cil_nodecon**)a;
+ bnodecon = *(struct cil_nodecon**)b;
+
+ /* sort ipv4 before ipv6 */
+ if (anodecon->addr->family != bnodecon->addr->family) {
+ if (anodecon->addr->family == AF_INET) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ /* most specific netmask goes first, then order by ip addr */
+ if (anodecon->addr->family == AF_INET) {
+ int rc = memcmp(&anodecon->mask->ip.v4, &bnodecon->mask->ip.v4, sizeof(anodecon->mask->ip.v4));
+ if (rc != 0) {
+ return -1 * rc;
+ }
+ return memcmp(&anodecon->addr->ip.v4, &bnodecon->addr->ip.v4, sizeof(anodecon->addr->ip.v4));
+ } else {
+ int rc = memcmp(&anodecon->mask->ip.v6, &bnodecon->mask->ip.v6, sizeof(anodecon->mask->ip.v6));
+ if (rc != 0) {
+ return -1 * rc;
+ }
+ return memcmp(&anodecon->addr->ip.v6, &bnodecon->addr->ip.v6, sizeof(anodecon->addr->ip.v6));
+ }
+}
+
+int cil_post_pirqcon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_pirqcon *apirqcon = *(struct cil_pirqcon**)a;
+ struct cil_pirqcon *bpirqcon = *(struct cil_pirqcon**)b;
+
+ if (apirqcon->pirq < bpirqcon->pirq) {
+ rc = -1;
+ } else if (bpirqcon->pirq < apirqcon->pirq) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int cil_post_iomemcon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_iomemcon *aiomemcon = *(struct cil_iomemcon**)a;
+ struct cil_iomemcon *biomemcon = *(struct cil_iomemcon**)b;
+
+ rc = (aiomemcon->iomem_high - aiomemcon->iomem_low)
+ - (biomemcon->iomem_high - biomemcon->iomem_low);
+ if (rc == 0) {
+ if (aiomemcon->iomem_low < biomemcon->iomem_low) {
+ rc = -1;
+ } else if (biomemcon->iomem_low < aiomemcon->iomem_low) {
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
+
+int cil_post_ioportcon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_ioportcon *aioportcon = *(struct cil_ioportcon**)a;
+ struct cil_ioportcon *bioportcon = *(struct cil_ioportcon**)b;
+
+ rc = (aioportcon->ioport_high - aioportcon->ioport_low)
+ - (bioportcon->ioport_high - bioportcon->ioport_low);
+ if (rc == 0) {
+ if (aioportcon->ioport_low < bioportcon->ioport_low) {
+ rc = -1;
+ } else if (bioportcon->ioport_low < aioportcon->ioport_low) {
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
+
+int cil_post_pcidevicecon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_pcidevicecon *apcidevicecon = *(struct cil_pcidevicecon**)a;
+ struct cil_pcidevicecon *bpcidevicecon = *(struct cil_pcidevicecon**)b;
+
+ if (apcidevicecon->dev < bpcidevicecon->dev) {
+ rc = -1;
+ } else if (bpcidevicecon->dev < apcidevicecon->dev) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int cil_post_devicetreecon_compare(const void *a, const void *b)
+{
+ int rc = SEPOL_ERR;
+ struct cil_devicetreecon *adevicetreecon = *(struct cil_devicetreecon**)a;
+ struct cil_devicetreecon *bdevicetreecon = *(struct cil_devicetreecon**)b;
+
+ rc = strcmp(adevicetreecon->path, bdevicetreecon->path);
+
+ return rc;
+}
+
+int cil_post_fsuse_compare(const void *a, const void *b)
+{
+ int rc;
+ struct cil_fsuse *afsuse;
+ struct cil_fsuse *bfsuse;
+ afsuse = *(struct cil_fsuse**)a;
+ bfsuse = *(struct cil_fsuse**)b;
+ if (afsuse->type < bfsuse->type) {
+ rc = -1;
+ } else if (bfsuse->type < afsuse->type) {
+ rc = 1;
+ } else {
+ rc = strcmp(afsuse->fs_str, bfsuse->fs_str);
+ }
+ return rc;
+}
+
+static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ struct cil_db *db = extra_args;
+
+ switch(node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO:
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ case CIL_CLASS: {
+ struct cil_class *class = node->data;
+ if (class->datum.nodes->head->data == node) {
+ // Multiple nodes can point to the same datum. Only count once.
+ db->num_classes++;
+ }
+ break;
+ }
+ case CIL_TYPE: {
+ struct cil_type *type = node->data;
+ if (type->datum.nodes->head->data == node) {
+ // Multiple nodes can point to the same datum. Only count once.
+ type->value = db->num_types;
+ db->num_types++;
+ db->num_types_and_attrs++;
+ }
+ break;
+ }
+ case CIL_TYPEATTRIBUTE: {
+ struct cil_typeattribute *attr = node->data;
+ if (attr->datum.nodes->head->data == node) {
+ // Multiple nodes can point to the same datum. Only count once.
+ db->num_types_and_attrs++;
+ }
+ break;
+ }
+
+ case CIL_ROLE: {
+ struct cil_role *role = node->data;
+ if (role->datum.nodes->head->data == node) {
+ // Multiple nodes can point to the same datum. Only count once.
+ role->value = db->num_roles;
+ db->num_roles++;
+ }
+ break;
+ }
+ case CIL_USER: {
+ struct cil_user *user = node->data;
+ if (user->datum.nodes->head->data == node) {
+ // multiple AST nodes can point to the same cil_user data (like if
+ // copied from a macro). This check ensures we only count the
+ // duplicates once
+ user->value = db->num_users;
+ db->num_users++;
+ }
+ break;
+ }
+ case CIL_NETIFCON:
+ db->netifcon->count++;
+ break;
+ case CIL_GENFSCON:
+ db->genfscon->count++;
+ break;
+ case CIL_FILECON:
+ db->filecon->count++;
+ break;
+ case CIL_NODECON:
+ db->nodecon->count++;
+ break;
+ case CIL_PORTCON:
+ db->portcon->count++;
+ break;
+ case CIL_PIRQCON:
+ db->pirqcon->count++;
+ break;
+ case CIL_IOMEMCON:
+ db->iomemcon->count++;
+ break;
+ case CIL_IOPORTCON:
+ db->ioportcon->count++;
+ break;
+ case CIL_PCIDEVICECON:
+ db->pcidevicecon->count++;
+ break;
+ case CIL_DEVICETREECON:
+ db->devicetreecon->count++;
+ break;
+ case CIL_FSUSE:
+ db->fsuse->count++;
+ break;
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __cil_post_db_array_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ struct cil_db *db = extra_args;
+
+ switch(node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO:
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ case CIL_TYPE: {
+ struct cil_type *type = node->data;
+ if (db->val_to_type == NULL) {
+ db->val_to_type = cil_malloc(sizeof(*db->val_to_type) * db->num_types);
+ }
+ db->val_to_type[type->value] = type;
+ break;
+ }
+ case CIL_ROLE: {
+ struct cil_role *role = node->data;
+ if (db->val_to_role == NULL) {
+ db->val_to_role = cil_malloc(sizeof(*db->val_to_role) * db->num_roles);
+ }
+ db->val_to_role[role->value] = role;
+ break;
+ }
+ case CIL_USER: {
+ struct cil_user *user= node->data;
+ if (db->val_to_user == NULL) {
+ db->val_to_user = cil_malloc(sizeof(*db->val_to_user) * db->num_users);
+ }
+ db->val_to_user[user->value] = user;
+ break;
+ }
+ case CIL_USERPREFIX: {
+ cil_list_append(db->userprefixes, CIL_USERPREFIX, node->data);
+ break;
+ }
+ case CIL_SELINUXUSER: {
+ cil_list_prepend(db->selinuxusers, CIL_SELINUXUSER, node->data);
+ break;
+ }
+ case CIL_SELINUXUSERDEFAULT: {
+ cil_list_append(db->selinuxusers, CIL_SELINUXUSERDEFAULT, node->data);
+ break;
+ }
+ case CIL_NETIFCON: {
+ struct cil_sort *sort = db->netifcon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_FSUSE: {
+ struct cil_sort *sort = db->fsuse;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_GENFSCON: {
+ struct cil_sort *sort = db->genfscon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_FILECON: {
+ struct cil_sort *sort = db->filecon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_NODECON: {
+ struct cil_sort *sort = db->nodecon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_PORTCON: {
+ struct cil_sort *sort = db->portcon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_PIRQCON: {
+ struct cil_sort *sort = db->pirqcon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_IOMEMCON: {
+ struct cil_sort *sort = db->iomemcon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_IOPORTCON: {
+ struct cil_sort *sort = db->ioportcon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_PCIDEVICECON: {
+ struct cil_sort *sort = db->pcidevicecon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ case CIL_DEVICETREECON: {
+ struct cil_sort *sort = db->devicetreecon;
+ uint32_t count = sort->count;
+ uint32_t i = sort->index;
+ if (sort->array == NULL) {
+ sort->array = cil_malloc(sizeof(*sort->array)*count);
+ }
+ sort->array[i] = node->data;
+ sort->index++;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __evaluate_type_expression(struct cil_typeattribute *attr, struct cil_db *db)
+{
+ int rc;
+
+ attr->types = cil_malloc(sizeof(*attr->types));
+ rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->types, db->num_types, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to expand type attribute to bitmap\n");
+ ebitmap_destroy(attr->types);
+ free(attr->types);
+ attr->types = NULL;
+ }
+ return rc;
+}
+
+static int __cil_type_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ ebitmap_init(bitmap);
+
+ if (node->flavor == CIL_TYPEATTRIBUTE) {
+ struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+ if (attr->types == NULL) {
+ rc = __evaluate_type_expression(attr, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ ebitmap_union(bitmap, attr->types);
+ } else if (node->flavor == CIL_TYPEALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)datum;
+ struct cil_type *type = alias->actual;
+ if (ebitmap_set_bit(bitmap, type->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set type bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ } else {
+ struct cil_type *type = (struct cil_type *)datum;
+ if (ebitmap_set_bit(bitmap, type->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set type bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __evaluate_user_expression(struct cil_userattribute *attr, struct cil_db *db)
+{
+ int rc;
+
+ attr->users = cil_malloc(sizeof(*attr->users));
+ rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->users, db->num_users, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to expand user attribute to bitmap\n");
+ ebitmap_destroy(attr->users);
+ free(attr->users);
+ attr->users = NULL;
+ }
+ return rc;
+}
+
+static int __cil_user_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *node = datum->nodes->head->data;
+ struct cil_userattribute *attr = NULL;
+ struct cil_user *user = NULL;
+
+ ebitmap_init(bitmap);
+
+ if (node->flavor == CIL_USERATTRIBUTE) {
+ attr = (struct cil_userattribute *)datum;
+ if (attr->users == NULL) {
+ rc = __evaluate_user_expression(attr, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ ebitmap_union(bitmap, attr->users);
+ } else {
+ user = (struct cil_user *)datum;
+ if (ebitmap_set_bit(bitmap, user->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set user bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __evaluate_role_expression(struct cil_roleattribute *attr, struct cil_db *db)
+{
+ int rc;
+
+ attr->roles = cil_malloc(sizeof(*attr->roles));
+ rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->roles, db->num_roles, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to expand role attribute to bitmap\n");
+ ebitmap_destroy(attr->roles);
+ free(attr->roles);
+ attr->roles = NULL;
+ }
+ return rc;
+}
+
+static int __cil_role_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ ebitmap_init(bitmap);
+
+ if (node->flavor == CIL_ROLEATTRIBUTE) {
+ struct cil_roleattribute *attr = (struct cil_roleattribute *)datum;
+ if (attr->roles == NULL) {
+ rc = __evaluate_role_expression(attr, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ ebitmap_union(bitmap, attr->roles);
+ } else {
+ struct cil_role *role = (struct cil_role *)datum;
+ if (ebitmap_set_bit(bitmap, role->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set role bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __evaluate_permissionx_expression(struct cil_permissionx *permx, struct cil_db *db)
+{
+ int rc;
+
+ permx->perms = cil_malloc(sizeof(*permx->perms));
+ ebitmap_init(permx->perms);
+
+ rc = __cil_expr_to_bitmap(permx->expr_str, permx->perms, 0x10000, db); // max is one more than 0xFFFF
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to expand permissionx expression\n");
+ ebitmap_destroy(permx->perms);
+ free(permx->perms);
+ permx->perms = NULL;
+ }
+
+ return rc;
+}
+
+static int __cil_permx_str_to_int(char *permx_str, uint16_t *val)
+{
+ char *endptr = NULL;
+ long lval = strtol(permx_str, &endptr, 0);
+
+ if (*endptr != '\0') {
+ cil_log(CIL_ERR, "permissionx value %s not valid number\n", permx_str);
+ goto exit;
+ }
+ if (lval < 0x0000 || lval > 0xFFFF) {
+ cil_log(CIL_ERR, "permissionx value %s must be between 0x0000 and 0xFFFF\n", permx_str);
+ goto exit;
+ }
+
+ *val = (uint16_t)lval;
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_permx_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ uint16_t val;
+
+ ebitmap_init(bitmap);
+
+ rc = __cil_permx_str_to_int((char*)datum, &val);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (ebitmap_set_bit(bitmap, (unsigned int)val, 1)) {
+ cil_log(CIL_ERR, "Failed to set permissionx bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_perm_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
+{
+ struct cil_perm *perm = (struct cil_perm *)datum;
+ unsigned int value = perm->value;
+
+ ebitmap_init(bitmap);
+ if (ebitmap_set_bit(bitmap, value, 1)) {
+ cil_log(CIL_INFO, "Failed to set perm bit\n");
+ ebitmap_destroy(bitmap);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __evaluate_cat_expression(struct cil_cats *cats, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ ebitmap_t bitmap;
+ struct cil_list *new;
+ struct cil_list_item *curr;
+
+ if (cats->evaluated == CIL_TRUE) {
+ return SEPOL_OK;
+ }
+
+ if (cil_verify_is_list(cats->datum_expr, CIL_CAT)) {
+ return SEPOL_OK;
+ }
+
+ ebitmap_init(&bitmap);
+ rc = __cil_expr_to_bitmap(cats->datum_expr, &bitmap, db->num_cats, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to expand category expression to bitmap\n");
+ ebitmap_destroy(&bitmap);
+ goto exit;
+ }
+
+ cil_list_init(&new, CIL_CAT);
+
+ cil_list_for_each(curr, db->catorder) {
+ struct cil_cat *cat = curr->data;
+ if (ebitmap_get_bit(&bitmap, cat->value)) {
+ cil_list_append(new, CIL_DATUM, cat);
+ }
+ }
+
+ ebitmap_destroy(&bitmap);
+ cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+ if (new->head != NULL) {
+ cats->datum_expr = new;
+ } else {
+ /* empty list */
+ cil_list_destroy(&new, CIL_FALSE);
+ cats->datum_expr = NULL;
+ }
+
+ cats->evaluated = CIL_TRUE;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_cat_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ ebitmap_init(bitmap);
+
+ if (node->flavor == CIL_CATSET) {
+ struct cil_catset *catset = (struct cil_catset *)datum;
+ struct cil_list_item *curr;
+ if (catset->cats->evaluated == CIL_FALSE) {
+ rc = __evaluate_cat_expression(catset->cats, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ for (curr = catset->cats->datum_expr->head; curr; curr = curr->next) {
+ struct cil_cat *cat = (struct cil_cat *)curr->data;
+ if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set cat bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+ } else if (node->flavor == CIL_CATALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)datum;
+ struct cil_cat *cat = alias->actual;
+ if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set cat bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ } else {
+ struct cil_cat *cat = (struct cil_cat *)datum;
+ if (ebitmap_set_bit(bitmap, cat->value, 1)) {
+ cil_log(CIL_ERR, "Failed to set cat bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_cat_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
+{
+ int rc = SEPOL_ERR;
+ struct cil_symtab_datum *d1 = i1->data;
+ struct cil_symtab_datum *d2 = i2->data;
+ struct cil_tree_node *n1 = d1->nodes->head->data;
+ struct cil_tree_node *n2 = d2->nodes->head->data;
+ struct cil_cat *c1 = (struct cil_cat *)d1;
+ struct cil_cat *c2 = (struct cil_cat *)d2;
+ int i;
+
+ if (n1->flavor == CIL_CATSET || n2->flavor == CIL_CATSET) {
+ cil_log(CIL_ERR, "Category sets cannont be used in a category range\n");
+ goto exit;
+ }
+
+ if (n1->flavor == CIL_CATALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)d1;
+ c1 = alias->actual;
+ }
+
+ if (n2->flavor == CIL_CATALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)d2;
+ c2 = alias->actual;
+ }
+
+ for (i = c1->value; i <= c2->value; i++) {
+ if (ebitmap_set_bit(bitmap, i, 1)) {
+ cil_log(CIL_ERR, "Failed to set cat bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_permissionx_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
+{
+ int rc = SEPOL_ERR;
+ char *p1 = i1->data;
+ char *p2 = i2->data;
+ uint16_t v1;
+ uint16_t v2;
+ uint32_t i;
+
+ rc = __cil_permx_str_to_int(p1, &v1);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_permx_str_to_int(p2, &v2);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ for (i = v1; i <= v2; i++) {
+ if (ebitmap_set_bit(bitmap, i, 1)) {
+ cil_log(CIL_ERR, "Failed to set permissionx bit\n");
+ ebitmap_destroy(bitmap);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flavor flavor, ebitmap_t *bitmap, int max, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+
+ if (curr->flavor == CIL_DATUM) {
+ switch (flavor) {
+ case CIL_TYPE:
+ rc = __cil_type_to_bitmap(curr->data, bitmap, db);
+ break;
+ case CIL_ROLE:
+ rc = __cil_role_to_bitmap(curr->data, bitmap, db);
+ break;
+ case CIL_USER:
+ rc = __cil_user_to_bitmap(curr->data, bitmap, db);
+ break;
+ case CIL_PERM:
+ rc = __cil_perm_to_bitmap(curr->data, bitmap, db);
+ break;
+ case CIL_CAT:
+ rc = __cil_cat_to_bitmap(curr->data, bitmap, db);
+ break;
+ default:
+ rc = SEPOL_ERR;
+ }
+ } else if (curr->flavor == CIL_LIST) {
+ struct cil_list *l = curr->data;
+ ebitmap_init(bitmap);
+ rc = __cil_expr_to_bitmap(l, bitmap, max, db);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(bitmap);
+ }
+ } else if (flavor == CIL_PERMISSIONX) {
+ // permissionx expressions aren't resolved into anything, so curr->flavor
+ // is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those
+ rc = __cil_permx_to_bitmap(curr->data, bitmap, db);
+ }
+
+ return rc;
+}
+
+static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ enum cil_flavor flavor;
+ ebitmap_t tmp, b1, b2;
+
+ if (expr == NULL || expr->head == NULL) {
+ return SEPOL_OK;
+ }
+
+ curr = expr->head;
+ flavor = expr->flavor;
+
+ if (curr->flavor == CIL_OP) {
+ enum cil_flavor op = (enum cil_flavor)curr->data;
+
+ if (op == CIL_ALL) {
+ ebitmap_init(&b1); /* all zeros */
+ rc = ebitmap_not(&tmp, &b1, max);
+ ebitmap_destroy(&b1);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to expand 'all' operator\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ } else if (op == CIL_RANGE) {
+ if (flavor == CIL_CAT) {
+ ebitmap_init(&tmp);
+ rc = __cil_cat_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to expand category range\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ } else if (flavor == CIL_PERMISSIONX) {
+ ebitmap_init(&tmp);
+ rc = __cil_permissionx_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to expand category range\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_INFO, "Range operation only supported for categories permissionx\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ rc = __cil_expr_to_bitmap_helper(curr->next, flavor, &b1, max, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get first operand bitmap\n");
+ goto exit;
+ }
+
+ if (op == CIL_NOT) {
+ rc = ebitmap_not(&tmp, &b1, max);
+ ebitmap_destroy(&b1);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to NOT bitmap\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ } else {
+ rc = __cil_expr_to_bitmap_helper(curr->next->next, flavor, &b2, max, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get second operand bitmap\n");
+ goto exit;
+ }
+
+ if (op == CIL_OR) {
+ rc = ebitmap_or(&tmp, &b1, &b2);
+ } else if (op == CIL_AND) {
+ rc = ebitmap_and(&tmp, &b1, &b2);
+ } else if (op == CIL_XOR) {
+ rc = ebitmap_xor(&tmp, &b1, &b2);
+ } else {
+ rc = SEPOL_ERR;
+ }
+ ebitmap_destroy(&b1);
+ ebitmap_destroy(&b2);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to apply operator to bitmaps\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ }
+ }
+ } else {
+ ebitmap_init(&tmp);
+ for (;curr; curr = curr->next) {
+ rc = __cil_expr_to_bitmap_helper(curr, flavor, &b2, max, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to get operand in list\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+ b1 = tmp;
+ rc = ebitmap_or(&tmp, &b1, &b2);
+ ebitmap_destroy(&b1);
+ ebitmap_destroy(&b2);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to OR operands in list\n");
+ ebitmap_destroy(&tmp);
+ goto exit;
+ }
+
+ }
+ }
+
+ ebitmap_union(out, &tmp);
+ ebitmap_destroy(&tmp);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *expr;
+
+ ebitmap_init(out);
+
+ if (expr_list == NULL) {
+ return SEPOL_OK;
+ }
+
+ cil_list_for_each(expr, expr_list) {
+ ebitmap_t bitmap;
+ struct cil_list *l = (struct cil_list *)expr->data;
+ ebitmap_init(&bitmap);
+ rc = __cil_expr_to_bitmap(l, &bitmap, max, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to expand expression list to bitmap\n");
+ ebitmap_destroy(&bitmap);
+ goto exit;
+ }
+ ebitmap_union(out, &bitmap);
+ ebitmap_destroy(&bitmap);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_post_db_attr_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_db *db = extra_args;
+
+ switch (node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO: {
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ }
+ case CIL_TYPEATTRIBUTE: {
+ struct cil_typeattribute *attr = node->data;
+ if (attr->types == NULL) {
+ rc = __evaluate_type_expression(attr, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ break;
+ }
+ case CIL_ROLEATTRIBUTE: {
+ struct cil_roleattribute *attr = node->data;
+ if (attr->roles == NULL) {
+ rc = __evaluate_role_expression(attr, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ break;
+ }
+ case CIL_AVRULEX: {
+ struct cil_avrule *rule = node->data;
+ if (rule->perms.x.permx_str == NULL) {
+ rc = __evaluate_permissionx_expression(rule->perms.x.permx, db);
+ if (rc != SEPOL_OK) goto exit;
+ }
+ break;
+ }
+ case CIL_PERMISSIONX: {
+ struct cil_permissionx *permx = node->data;
+ rc = __evaluate_permissionx_expression(permx, db);
+ if (rc != SEPOL_OK) goto exit;
+ break;
+ }
+ case CIL_USERATTRIBUTE: {
+ struct cil_userattribute *attr = node->data;
+ if (attr->users == NULL) {
+ rc = __evaluate_user_expression(attr, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_role_assign_types(struct cil_role *role, struct cil_symtab_datum *datum)
+{
+ struct cil_tree_node *node = datum->nodes->head->data;
+
+ if (role->types == NULL) {
+ role->types = cil_malloc(sizeof(*role->types));
+ ebitmap_init(role->types);
+ }
+
+ if (node->flavor == CIL_TYPE) {
+ struct cil_type *type = (struct cil_type *)datum;
+ if (ebitmap_set_bit(role->types, type->value, 1)) {
+ cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
+ goto exit;
+ }
+ } else if (node->flavor == CIL_TYPEALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)datum;
+ struct cil_type *type = alias->actual;
+ if (ebitmap_set_bit(role->types, type->value, 1)) {
+ cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
+ goto exit;
+ }
+ } else if (node->flavor == CIL_TYPEATTRIBUTE) {
+ struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
+ ebitmap_union(role->types, attr->types);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_post_db_roletype_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_db *db = extra_args;
+
+ switch (node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO: {
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ }
+ case CIL_ROLETYPE: {
+ struct cil_roletype *roletype = node->data;
+ struct cil_symtab_datum *role_datum = roletype->role;
+ struct cil_symtab_datum *type_datum = roletype->type;
+ struct cil_tree_node *role_node = role_datum->nodes->head->data;
+
+ if (role_node->flavor == CIL_ROLEATTRIBUTE) {
+ struct cil_roleattribute *attr = roletype->role;
+ ebitmap_node_t *rnode;
+ unsigned int i;
+
+ ebitmap_for_each_bit(attr->roles, rnode, i) {
+ struct cil_role *role = NULL;
+
+ if (!ebitmap_get_bit(attr->roles, i)) {
+ continue;
+ }
+
+ role = db->val_to_role[i];
+
+ rc = __cil_role_assign_types(role, type_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ struct cil_role *role = roletype->role;
+
+ rc = __cil_role_assign_types(role, type_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_log(CIL_INFO, "cil_post_db_roletype_helper failed\n");
+ return rc;
+}
+
+static int __cil_user_assign_roles(struct cil_user *user, struct cil_symtab_datum *datum)
+{
+ struct cil_tree_node *node = datum->nodes->head->data;
+ struct cil_role *role = NULL;
+ struct cil_roleattribute *attr = NULL;
+
+ if (user->roles == NULL) {
+ user->roles = cil_malloc(sizeof(*user->roles));
+ ebitmap_init(user->roles);
+ }
+
+ if (node->flavor == CIL_ROLE) {
+ role = (struct cil_role *)datum;
+ if (ebitmap_set_bit(user->roles, role->value, 1)) {
+ cil_log(CIL_INFO, "Failed to set bit in user roles bitmap\n");
+ goto exit;
+ }
+ } else if (node->flavor == CIL_ROLEATTRIBUTE) {
+ attr = (struct cil_roleattribute *)datum;
+ ebitmap_union(user->roles, attr->roles);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_post_db_userrole_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_db *db = extra_args;
+ struct cil_block *blk = NULL;
+ struct cil_userrole *userrole = NULL;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *role_datum = NULL;
+ struct cil_tree_node *user_node = NULL;
+ struct cil_userattribute *u_attr = NULL;
+ unsigned int i;
+ struct cil_user *user = NULL;
+ ebitmap_node_t *unode = NULL;
+
+ switch (node->flavor) {
+ case CIL_BLOCK: {
+ blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO: {
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ }
+ case CIL_USERROLE: {
+ userrole = node->data;
+ user_datum = userrole->user;
+ role_datum = userrole->role;
+ user_node = user_datum->nodes->head->data;
+
+ if (user_node->flavor == CIL_USERATTRIBUTE) {
+ u_attr = userrole->user;
+
+ ebitmap_for_each_bit(u_attr->users, unode, i) {
+ if (!ebitmap_get_bit(u_attr->users, i)) {
+ continue;
+ }
+
+ user = db->val_to_user[i];
+
+ rc = __cil_user_assign_roles(user, role_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ user = userrole->user;
+
+ rc = __cil_user_assign_roles(user, role_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_log(CIL_INFO, "cil_post_db_userrole_helper failed\n");
+ return rc;
+}
+
+static int __evaluate_level_expression(struct cil_level *level, struct cil_db *db)
+{
+ if (level->cats != NULL) {
+ return __evaluate_cat_expression(level->cats, db);
+ }
+
+ return SEPOL_OK;
+}
+
+static int __evaluate_levelrange_expression(struct cil_levelrange *levelrange, struct cil_db *db)
+{
+ int rc = SEPOL_OK;
+
+ if (levelrange->low != NULL && levelrange->low->cats != NULL) {
+ rc = __evaluate_cat_expression(levelrange->low->cats, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ if (levelrange->high != NULL && levelrange->high->cats != NULL) {
+ rc = __evaluate_cat_expression(levelrange->high->cats, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int __cil_post_db_cat_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_db *db = extra_args;
+
+ switch (node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO: {
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ }
+ case CIL_CATSET: {
+ struct cil_catset *catset = node->data;
+ rc = __evaluate_cat_expression(catset->cats, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_SENSCAT: {
+ struct cil_senscat *senscat = node->data;
+ rc = __evaluate_cat_expression(senscat->cats, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_LEVEL: {
+ rc = __evaluate_level_expression(node->data, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_LEVELRANGE: {
+ rc = __evaluate_levelrange_expression(node->data, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_USER: {
+ struct cil_user *user = node->data;
+ rc = __evaluate_level_expression(user->dftlevel, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rc = __evaluate_levelrange_expression(user->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_SELINUXUSERDEFAULT:
+ case CIL_SELINUXUSER: {
+ struct cil_selinuxuser *selinuxuser = node->data;
+ rc = __evaluate_levelrange_expression(selinuxuser->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_RANGETRANSITION: {
+ struct cil_rangetransition *rangetrans = node->data;
+ rc = __evaluate_levelrange_expression(rangetrans->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_CONTEXT: {
+ struct cil_context *context = node->data;
+ rc = __evaluate_levelrange_expression(context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_SIDCONTEXT: {
+ struct cil_sidcontext *sidcontext = node->data;
+ rc = __evaluate_levelrange_expression(sidcontext->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_FILECON: {
+ struct cil_filecon *filecon = node->data;
+ if (filecon->context) {
+ rc = __evaluate_levelrange_expression(filecon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ break;
+ }
+ case CIL_PORTCON: {
+ struct cil_portcon *portcon = node->data;
+ rc = __evaluate_levelrange_expression(portcon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_NODECON: {
+ struct cil_nodecon *nodecon = node->data;
+ rc = __evaluate_levelrange_expression(nodecon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_GENFSCON: {
+ struct cil_genfscon *genfscon = node->data;
+ rc = __evaluate_levelrange_expression(genfscon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_NETIFCON: {
+ struct cil_netifcon *netifcon = node->data;
+ rc = __evaluate_levelrange_expression(netifcon->if_context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rc = __evaluate_levelrange_expression(netifcon->packet_context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_PIRQCON: {
+ struct cil_pirqcon *pirqcon = node->data;
+ rc = __evaluate_levelrange_expression(pirqcon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_IOMEMCON: {
+ struct cil_iomemcon *iomemcon = node->data;
+ rc = __evaluate_levelrange_expression(iomemcon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_IOPORTCON: {
+ struct cil_ioportcon *ioportcon = node->data;
+ rc = __evaluate_levelrange_expression(ioportcon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_PCIDEVICECON: {
+ struct cil_pcidevicecon *pcidevicecon = node->data;
+ rc = __evaluate_levelrange_expression(pcidevicecon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_DEVICETREECON: {
+ struct cil_devicetreecon *devicetreecon = node->data;
+ rc = __evaluate_levelrange_expression(devicetreecon->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_FSUSE: {
+ struct cil_fsuse *fsuse = node->data;
+ rc = __evaluate_levelrange_expression(fsuse->context->range, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+struct perm_to_list {
+ enum cil_flavor flavor;
+ ebitmap_t *perms;
+ struct cil_list *new_list;
+};
+
+static int __perm_bits_to_list(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct perm_to_list *perm_args = (struct perm_to_list *)args;
+ ebitmap_t *perms = perm_args->perms;
+ struct cil_list *new_list = perm_args->new_list;
+ struct cil_perm *perm = (struct cil_perm *)d;
+ unsigned int value = perm->value;
+
+ if (!ebitmap_get_bit(perms, value)) {
+ return SEPOL_OK;
+ }
+
+ cil_list_append(new_list, CIL_DATUM, d);
+
+ return SEPOL_OK;
+}
+
+static int __evaluate_perm_expression(struct cil_list *perms, enum cil_flavor flavor, symtab_t *class_symtab, symtab_t *common_symtab, unsigned int num_perms, struct cil_list **new_list, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct perm_to_list args;
+ ebitmap_t bitmap;
+
+ if (cil_verify_is_list(perms, CIL_PERM)) {
+ return SEPOL_OK;
+ }
+
+ ebitmap_init(&bitmap);
+ rc = __cil_expr_to_bitmap(perms, &bitmap, num_perms, db);
+ if (rc != SEPOL_OK) {
+ ebitmap_destroy(&bitmap);
+ goto exit;
+ }
+
+ cil_list_init(new_list, flavor);
+
+ args.flavor = flavor;
+ args.perms = &bitmap;
+ args.new_list = *new_list;
+
+ cil_symtab_map(class_symtab, __perm_bits_to_list, &args);
+
+ if (common_symtab != NULL) {
+ cil_symtab_map(common_symtab, __perm_bits_to_list, &args);
+ }
+
+ ebitmap_destroy(&bitmap);
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __evaluate_classperms(struct cil_classperms *cp, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_class *class = cp->class;
+ struct cil_class *common = class->common;
+ symtab_t *common_symtab = NULL;
+ struct cil_list *new_list = NULL;
+
+ if (common) {
+ common_symtab = &common->perms;
+ }
+
+ rc = __evaluate_perm_expression(cp->perms, CIL_PERM, &class->perms, common_symtab, class->num_perms, &new_list, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (new_list == NULL) {
+ return SEPOL_OK;
+ }
+
+ cil_list_destroy(&cp->perms, CIL_FALSE);
+
+ cp->perms = new_list;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __evaluate_classperms_list(struct cil_list *classperms, struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ rc = __evaluate_classperms(cp, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ rc = __evaluate_classperms_list(cmp->classperms, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ rc = __evaluate_classperms_list(cp->classperms, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+struct class_map_args {
+ struct cil_db *db;
+ int rc;
+};
+
+static int __evaluate_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct class_map_args *map_args = args;
+ struct cil_perm *cmp = (struct cil_perm *)d;
+
+ int rc = __evaluate_classperms_list(cmp->classperms, map_args->db);
+
+ if (rc != SEPOL_OK) {
+ map_args->rc = rc;
+ }
+
+ return SEPOL_OK;
+}
+
+static int __evaluate_map_class(struct cil_class *mc, struct cil_db *db)
+{
+ struct class_map_args map_args;
+
+ map_args.db = db;
+ map_args.rc = SEPOL_OK;
+ cil_symtab_map(&mc->perms, __evaluate_map_perm_classperms, &map_args);
+
+ return map_args.rc;
+}
+
+static int __cil_post_db_classperms_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_db *db = extra_args;
+
+ switch (node->flavor) {
+ case CIL_BLOCK: {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ break;
+ }
+ case CIL_MACRO:
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ case CIL_MAP_CLASS: {
+ rc = __evaluate_map_class(node->data, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_CLASSPERMISSION: {
+ struct cil_classpermission *cp = node->data;
+ rc = __evaluate_classperms_list(cp->classperms, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_AVRULE: {
+ struct cil_avrule *avrule = node->data;
+ rc = __evaluate_classperms_list(avrule->perms.classperms, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ case CIL_CONSTRAIN:
+ case CIL_MLSCONSTRAIN: {
+ struct cil_constrain *constrain = node->data;
+ rc = __evaluate_classperms_list(constrain->classperms, db);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int cil_post_db(struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_count_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure during cil databse count helper\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_array_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failure during cil database array helper\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_attr_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to create attribute bitmaps\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_roletype_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed during roletype association\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_userrole_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed during userrole association\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_classperms_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to evaluate class mapping permissions expressions\n");
+ goto exit;
+ }
+
+ rc = cil_tree_walk(db->ast->root, __cil_post_db_cat_helper, NULL, NULL, db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Failed to evaluate category expressions\n");
+ goto exit;
+ }
+
+ qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
+ qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
+ qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
+ qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
+ qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
+ qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
+ qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
+ qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
+ qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
+ qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
+ qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
+
+exit:
+ return rc;
+}
+
+static int cil_post_verify(struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ int avrule_cnt = 0;
+ int handleunknown = -1;
+ int mls = -1;
+ int nseuserdflt = 0;
+ int pass = 0;
+ struct cil_args_verify extra_args;
+ struct cil_complex_symtab csymtab;
+
+ cil_complex_symtab_init(&csymtab, CIL_CLASS_SYM_SIZE);
+
+ extra_args.db = db;
+ extra_args.csymtab = &csymtab;
+ extra_args.avrule_cnt = &avrule_cnt;
+ extra_args.handleunknown = &handleunknown;
+ extra_args.mls = &mls;
+ extra_args.nseuserdflt = &nseuserdflt;
+ extra_args.pass = &pass;
+
+ for (pass = 0; pass < 2; pass++) {
+ rc = cil_tree_walk(db->ast->root, __cil_verify_helper, NULL, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to verify cil database\n");
+ goto exit;
+ }
+ }
+
+ if (db->handle_unknown == -1) {
+ if (handleunknown == -1) {
+ db->handle_unknown = SEPOL_DENY_UNKNOWN;
+ } else {
+ db->handle_unknown = handleunknown;
+ }
+ }
+
+ if (db->mls == -1) {
+ if (mls == -1) {
+ db->mls = CIL_FALSE;
+ } else {
+ db->mls = mls;
+ }
+ }
+
+ if (avrule_cnt == 0) {
+ cil_log(CIL_ERR, "Policy must include at least one avrule\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (nseuserdflt > 1) {
+ cil_log(CIL_ERR, "Policy cannot contain more than one selinuxuserdefault, found: %d\n", nseuserdflt);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+exit:
+ cil_complex_symtab_destroy(&csymtab);
+ return rc;
+}
+
+static int cil_pre_verify(struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_verify extra_args;
+
+ extra_args.db = db;
+
+ rc = cil_tree_walk(db->ast->root, __cil_pre_verify_helper, NULL, NULL, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to verify cil database\n");
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+int cil_post_process(struct cil_db *db)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_pre_verify(db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to verify cil database\n");
+ goto exit;
+ }
+
+ rc = cil_post_db(db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed post db handling\n");
+ goto exit;
+ }
+
+ rc = cil_post_verify(db);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to verify cil database\n");
+ goto exit;
+ }
+
+exit:
+ return rc;
+
+}
diff --git a/libsepol/cil/src/cil_post.h b/libsepol/cil/src/cil_post.h
new file mode 100644
index 0000000..74393cc
--- /dev/null
+++ b/libsepol/cil/src/cil_post.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_POST_H_
+#define CIL_POST_H_
+
+struct fc_data {
+ int meta;
+ int stem_len;
+ int str_len;
+};
+
+void cil_post_fc_fill_data(struct fc_data *fc, char *path);
+int cil_post_filecon_compare(const void *a, const void *b);
+int cil_post_portcon_compare(const void *a, const void *b);
+int cil_post_genfscon_compare(const void *a, const void *b);
+int cil_post_netifcon_compare(const void *a, const void *b);
+int cil_post_nodecon_compare(const void *a, const void *b);
+int cil_post_fsuse_compare(const void *a, const void *b);
+
+int cil_post_context_sort(struct cil_db *db);
+
+int cil_post_process(struct cil_db *db);
+
+#endif
diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
new file mode 100644
index 0000000..de00679
--- /dev/null
+++ b/libsepol/cil/src/cil_reset_ast.c
@@ -0,0 +1,571 @@
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_list.h"
+#include "cil_symtab.h"
+
+static inline void cil_reset_classperms_list(struct cil_list *cp_list);
+static inline void cil_reset_level(struct cil_level *level);
+static inline void cil_reset_levelrange(struct cil_levelrange *levelrange);
+static inline void cil_reset_context(struct cil_context *context);
+
+
+static int __class_reset_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct cil_perm *perm = (struct cil_perm *)d;
+
+ perm->value -= *((int *)args);
+
+ return SEPOL_OK;
+}
+
+static void cil_reset_class(struct cil_class *class)
+{
+ if (class->common != NULL) {
+ struct cil_class *common = class->common;
+ cil_symtab_map(&class->perms, __class_reset_perm_values, &common->num_perms);
+ /* during a re-resolve, we need to reset the common, so a classcommon
+ * statement isn't seen as a duplicate */
+ class->num_perms -= common->num_perms;
+ class->common = NULL; /* Must make this NULL or there will be an error when re-resolving */
+ }
+ class->ordered = CIL_FALSE;
+}
+
+static void cil_reset_perm(struct cil_perm *perm)
+{
+ cil_reset_classperms_list(perm->classperms);
+}
+
+static inline void cil_reset_classperms(struct cil_classperms *cp)
+{
+ if (cp == NULL) {
+ return;
+ }
+
+ cil_list_destroy(&cp->perms, CIL_FALSE);
+}
+
+static void cil_reset_classpermission(struct cil_classpermission *cp)
+{
+ if (cp == NULL) {
+ return;
+ }
+
+ cil_reset_classperms_list(cp->classperms);
+}
+
+static void cil_reset_classperms_set(struct cil_classperms_set *cp_set)
+{
+ cil_reset_classpermission(cp_set->set);
+}
+
+static inline void cil_reset_classperms_list(struct cil_list *cp_list)
+{
+ struct cil_list_item *curr;
+
+ if (cp_list == NULL) {
+ return;
+ }
+
+ cil_list_for_each(curr, cp_list) {
+ if (curr->flavor == CIL_CLASSPERMS) { /* KERNEL or MAP */
+ cil_reset_classperms(curr->data);
+ } else if (curr->flavor == CIL_CLASSPERMS_SET) { /* SET */
+ cil_reset_classperms_set(curr->data);
+ }
+ }
+}
+
+static void cil_reset_classpermissionset(struct cil_classpermissionset *cps)
+{
+ cil_reset_classperms_list(cps->classperms);
+}
+
+static void cil_reset_classmapping(struct cil_classmapping *cm)
+{
+ cil_reset_classperms_list(cm->classperms);
+}
+
+static void cil_reset_alias(struct cil_alias *alias)
+{
+ /* reset actual to NULL during a re-resolve */
+ alias->actual = NULL;
+}
+
+static void cil_reset_user(struct cil_user *user)
+{
+ /* reset the bounds to NULL during a re-resolve */
+ user->bounds = NULL;
+ user->dftlevel = NULL;
+ user->range = NULL;
+}
+
+static void cil_reset_userattr(struct cil_userattribute *attr)
+{
+ struct cil_list_item *expr = NULL;
+ struct cil_list_item *next = NULL;
+
+ /* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a userattribute statement */
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ expr = attr->expr_list->head;
+ while (expr != NULL) {
+ next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+}
+
+static void cil_reset_userattributeset(struct cil_userattributeset *uas)
+{
+ cil_list_destroy(&uas->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser)
+{
+ if (selinuxuser->range_str == NULL) {
+ cil_reset_levelrange(selinuxuser->range);
+ }
+}
+
+static void cil_reset_role(struct cil_role *role)
+{
+ /* reset the bounds to NULL during a re-resolve */
+ role->bounds = NULL;
+}
+
+static void cil_reset_roleattr(struct cil_roleattribute *attr)
+{
+ /* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a attributeroles statement */
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ struct cil_list_item *expr = attr->expr_list->head;
+ while (expr != NULL) {
+ struct cil_list_item *next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+}
+
+static void cil_reset_roleattributeset(struct cil_roleattributeset *ras)
+{
+ cil_list_destroy(&ras->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_type(struct cil_type *type)
+{
+ /* reset the bounds to NULL during a re-resolve */
+ type->bounds = NULL;
+}
+
+static void cil_reset_typeattr(struct cil_typeattribute *attr)
+{
+ /* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a attributetypes statement */
+ if (attr->expr_list != NULL) {
+ /* we don't want to destroy the expression stacks (cil_list) inside
+ * this list cil_list_destroy destroys sublists, so we need to do it
+ * manually */
+ struct cil_list_item *expr = attr->expr_list->head;
+ while (expr != NULL) {
+ struct cil_list_item *next = expr->next;
+ cil_list_item_destroy(&expr, CIL_FALSE);
+ expr = next;
+ }
+ free(attr->expr_list);
+ attr->expr_list = NULL;
+ }
+ attr->used = CIL_FALSE;
+}
+
+static void cil_reset_typeattributeset(struct cil_typeattributeset *tas)
+{
+ cil_list_destroy(&tas->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_avrule(struct cil_avrule *rule)
+{
+ cil_reset_classperms_list(rule->perms.classperms);
+}
+
+static void cil_reset_rangetransition(struct cil_rangetransition *rangetrans)
+{
+ if (rangetrans->range_str == NULL) {
+ cil_reset_levelrange(rangetrans->range);
+ }
+}
+
+static void cil_reset_sens(struct cil_sens *sens)
+{
+ /* during a re-resolve, we need to reset the categories associated with
+ * this sensitivity from a (sensitivitycategory) statement */
+ cil_list_destroy(&sens->cats_list, CIL_FALSE);
+ sens->ordered = CIL_FALSE;
+}
+
+static void cil_reset_cat(struct cil_cat *cat)
+{
+ cat->ordered = CIL_FALSE;
+}
+
+static inline void cil_reset_cats(struct cil_cats *cats)
+{
+ if (cats != NULL) {
+ cats->evaluated = CIL_FALSE;
+ cil_list_destroy(&cats->datum_expr, CIL_FALSE);
+ }
+}
+
+
+static void cil_reset_senscat(struct cil_senscat *senscat)
+{
+ cil_reset_cats(senscat->cats);
+}
+
+static void cil_reset_catset(struct cil_catset *catset)
+{
+ cil_reset_cats(catset->cats);
+}
+
+static inline void cil_reset_level(struct cil_level *level)
+{
+ cil_reset_cats(level->cats);
+}
+
+static inline void cil_reset_levelrange(struct cil_levelrange *levelrange)
+{
+ if (levelrange->low_str == NULL) {
+ cil_reset_level(levelrange->low);
+ }
+
+ if (levelrange->high_str == NULL) {
+ cil_reset_level(levelrange->high);
+ }
+}
+
+static inline void cil_reset_userlevel(struct cil_userlevel *userlevel)
+{
+ if (userlevel->level_str == NULL) {
+ cil_reset_level(userlevel->level);
+ }
+}
+
+static inline void cil_reset_userrange(struct cil_userrange *userrange)
+{
+ if (userrange->range_str == NULL) {
+ cil_reset_levelrange(userrange->range);
+ }
+}
+
+static inline void cil_reset_context(struct cil_context *context)
+{
+ if (context->range_str == NULL) {
+ cil_reset_levelrange(context->range);
+ }
+}
+
+static void cil_reset_sidcontext(struct cil_sidcontext *sidcontext)
+{
+ if (sidcontext->context_str == NULL) {
+ cil_reset_context(sidcontext->context);
+ }
+}
+
+static void cil_reset_filecon(struct cil_filecon *filecon)
+{
+ if (filecon->context_str == NULL && filecon->context != NULL) {
+ cil_reset_context(filecon->context);
+ }
+}
+
+static void cil_reset_portcon(struct cil_portcon *portcon)
+{
+ if (portcon->context_str == NULL) {
+ cil_reset_context(portcon->context);
+ }
+}
+
+static void cil_reset_nodecon(struct cil_nodecon *nodecon)
+{
+ if (nodecon->context_str == NULL) {
+ cil_reset_context(nodecon->context);
+ }
+}
+
+static void cil_reset_genfscon(struct cil_genfscon *genfscon)
+{
+ if (genfscon->context_str == NULL) {
+ cil_reset_context(genfscon->context);
+ }
+}
+
+static void cil_reset_netifcon(struct cil_netifcon *netifcon)
+{
+ if (netifcon->if_context_str == NULL) {
+ cil_reset_context(netifcon->if_context);
+ }
+
+ if (netifcon->packet_context_str == NULL) {
+ cil_reset_context(netifcon->packet_context);
+ }
+}
+
+static void cil_reset_pirqcon(struct cil_pirqcon *pirqcon)
+{
+ if (pirqcon->context_str == NULL) {
+ cil_reset_context(pirqcon->context);
+ }
+}
+
+static void cil_reset_iomemcon(struct cil_iomemcon *iomemcon)
+{
+ if (iomemcon->context_str == NULL) {
+ cil_reset_context(iomemcon->context);
+ }
+}
+
+static void cil_reset_ioportcon(struct cil_ioportcon *ioportcon)
+{
+ if (ioportcon->context_str == NULL) {
+ cil_reset_context(ioportcon->context);
+ }
+}
+
+static void cil_reset_pcidevicecon(struct cil_pcidevicecon *pcidevicecon)
+{
+ if (pcidevicecon->context_str == NULL) {
+ cil_reset_context(pcidevicecon->context);
+ }
+}
+
+static void cil_reset_devicetreecon(struct cil_devicetreecon *devicetreecon)
+{
+ if (devicetreecon->context_str == NULL) {
+ cil_reset_context(devicetreecon->context);
+ }
+}
+
+static void cil_reset_fsuse(struct cil_fsuse *fsuse)
+{
+ if (fsuse->context_str == NULL) {
+ cil_reset_context(fsuse->context);
+ }
+}
+
+static void cil_reset_sid(struct cil_sid *sid)
+{
+ /* reset the context to NULL during a re-resolve */
+ sid->context = NULL;
+ sid->ordered = CIL_FALSE;
+}
+
+static void cil_reset_constrain(struct cil_constrain *con)
+{
+ cil_reset_classperms_list(con->classperms);
+ cil_list_destroy(&con->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_validatetrans(struct cil_validatetrans *vt)
+{
+ cil_list_destroy(&vt->datum_expr, CIL_FALSE);
+}
+
+static void cil_reset_default(struct cil_default *def)
+{
+ cil_list_destroy(&def->class_datums, CIL_FALSE);
+}
+
+static void cil_reset_defaultrange(struct cil_defaultrange *def)
+{
+ cil_list_destroy(&def->class_datums, CIL_FALSE);
+}
+
+static void cil_reset_booleanif(struct cil_booleanif *bif)
+{
+ cil_list_destroy(&bif->datum_expr, CIL_FALSE);
+}
+
+int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+ switch (node->flavor) {
+ case CIL_CLASS:
+ cil_reset_class(node->data);
+ break;
+ case CIL_PERM:
+ case CIL_MAP_PERM:
+ cil_reset_perm(node->data);
+ break;
+ case CIL_CLASSPERMISSION:
+ cil_reset_classpermission(node->data);
+ break;
+ case CIL_CLASSPERMISSIONSET:
+ cil_reset_classpermissionset(node->data);
+ break;
+ case CIL_CLASSMAPPING:
+ cil_reset_classmapping(node->data);
+ break;
+ case CIL_TYPEALIAS:
+ case CIL_SENSALIAS:
+ case CIL_CATALIAS:
+ cil_reset_alias(node->data);
+ break;
+ case CIL_USERRANGE:
+ cil_reset_userrange(node->data);
+ break;
+ case CIL_USERLEVEL:
+ cil_reset_userlevel(node->data);
+ break;
+ case CIL_USER:
+ cil_reset_user(node->data);
+ break;
+ case CIL_USERATTRIBUTE:
+ cil_reset_userattr(node->data);
+ break;
+ case CIL_USERATTRIBUTESET:
+ cil_reset_userattributeset(node->data);
+ break;
+ case CIL_SELINUXUSERDEFAULT:
+ case CIL_SELINUXUSER:
+ cil_reset_selinuxuser(node->data);
+ break;
+ case CIL_ROLE:
+ cil_reset_role(node->data);
+ break;
+ case CIL_ROLEATTRIBUTE:
+ cil_reset_roleattr(node->data);
+ break;
+ case CIL_ROLEATTRIBUTESET:
+ cil_reset_roleattributeset(node->data);
+ break;
+ case CIL_TYPE:
+ cil_reset_type(node->data);
+ break;
+ case CIL_TYPEATTRIBUTE:
+ cil_reset_typeattr(node->data);
+ break;
+ case CIL_TYPEATTRIBUTESET:
+ cil_reset_typeattributeset(node->data);
+ break;
+ case CIL_RANGETRANSITION:
+ cil_reset_rangetransition(node->data);
+ break;
+ case CIL_AVRULE:
+ cil_reset_avrule(node->data);
+ break;
+ case CIL_SENS:
+ cil_reset_sens(node->data);
+ break;
+ case CIL_CAT:
+ cil_reset_cat(node->data);
+ break;
+ case CIL_SENSCAT:
+ cil_reset_senscat(node->data);
+ break;
+ case CIL_CATSET:
+ cil_reset_catset(node->data);
+ break;
+ case CIL_LEVEL:
+ cil_reset_level(node->data);
+ break;
+ case CIL_LEVELRANGE:
+ cil_reset_levelrange(node->data);
+ break;
+ case CIL_CONTEXT:
+ cil_reset_context(node->data);
+ break;
+ case CIL_SIDCONTEXT:
+ cil_reset_sidcontext(node->data);
+ break;
+ case CIL_FILECON:
+ cil_reset_filecon(node->data);
+ break;
+ case CIL_PORTCON:
+ cil_reset_portcon(node->data);
+ break;
+ case CIL_NODECON:
+ cil_reset_nodecon(node->data);
+ break;
+ case CIL_GENFSCON:
+ cil_reset_genfscon(node->data);
+ break;
+ case CIL_NETIFCON:
+ cil_reset_netifcon(node->data);
+ break;
+ case CIL_PIRQCON:
+ cil_reset_pirqcon(node->data);
+ break;
+ case CIL_IOMEMCON:
+ cil_reset_iomemcon(node->data);
+ break;
+ case CIL_IOPORTCON:
+ cil_reset_ioportcon(node->data);
+ break;
+ case CIL_PCIDEVICECON:
+ cil_reset_pcidevicecon(node->data);
+ break;
+ case CIL_DEVICETREECON:
+ cil_reset_devicetreecon(node->data);
+ break;
+ case CIL_FSUSE:
+ cil_reset_fsuse(node->data);
+ break;
+ case CIL_SID:
+ cil_reset_sid(node->data);
+ break;
+ case CIL_CONSTRAIN:
+ case CIL_MLSCONSTRAIN:
+ cil_reset_constrain(node->data);
+ break;
+ case CIL_VALIDATETRANS:
+ case CIL_MLSVALIDATETRANS:
+ cil_reset_validatetrans(node->data);
+ break;
+ case CIL_DEFAULTUSER:
+ case CIL_DEFAULTROLE:
+ case CIL_DEFAULTTYPE:
+ cil_reset_default(node->data);
+ break;
+ case CIL_DEFAULTRANGE:
+ cil_reset_defaultrange(node->data);
+ break;
+ case CIL_BOOLEANIF:
+ cil_reset_booleanif(node->data);
+ break;
+ case CIL_TUNABLEIF:
+ case CIL_CALL:
+ break; /* Not effected by optional block disabling */
+ case CIL_MACRO:
+ case CIL_SIDORDER:
+ case CIL_CLASSORDER:
+ case CIL_CATORDER:
+ case CIL_SENSITIVITYORDER:
+ break; /* Nothing to reset */
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_reset_ast(struct cil_tree_node *current)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_tree_walk(current, __cil_reset_node, NULL, NULL, NULL);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to reset AST\n");
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
diff --git a/libsepol/cil/src/cil_reset_ast.h b/libsepol/cil/src/cil_reset_ast.h
new file mode 100644
index 0000000..393ff9e
--- /dev/null
+++ b/libsepol/cil/src/cil_reset_ast.h
@@ -0,0 +1,8 @@
+#ifndef CIL_RESET_AST_H_
+#define CIL_RESET_AST_H_
+
+#include "cil_tree.h"
+
+int cil_reset_ast(struct cil_tree_node *current);
+
+#endif /* CIL_RESET_AST_H_ */
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
new file mode 100644
index 0000000..70e4462
--- /dev/null
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -0,0 +1,4097 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_build_ast.h"
+#include "cil_resolve_ast.h"
+#include "cil_reset_ast.h"
+#include "cil_copy_ast.h"
+#include "cil_verify.h"
+#include "cil_strpool.h"
+#include "cil_symtab.h"
+
+struct cil_args_resolve {
+ struct cil_db *db;
+ enum cil_pass pass;
+ uint32_t *changed;
+ char *last_resolved_name;
+ struct cil_tree_node *optstack;
+ struct cil_tree_node *boolif;
+ struct cil_tree_node *macro;
+ struct cil_tree_node *blockstack;
+ struct cil_list *sidorder_lists;
+ struct cil_list *classorder_lists;
+ struct cil_list *unordered_classorder_lists;
+ struct cil_list *catorder_lists;
+ struct cil_list *sensitivityorder_lists;
+ struct cil_list *in_list;
+};
+
+static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node)
+{
+ /* Currently only used for typetransition file names.
+ But could be used for any string that is passed as a parameter.
+ */
+ struct cil_tree_node *parent = ast_node->parent;
+ struct cil_macro *macro = NULL;
+ struct cil_name *name;
+ symtab_t *symtab;
+ enum cil_sym_index sym_index;
+ struct cil_symtab_datum *datum = NULL;
+
+ cil_flavor_to_symtab_index(CIL_NAME, &sym_index);
+ symtab = &((struct cil_root *)db->ast->root->data)->symtab[sym_index];
+
+ cil_symtab_get_datum(symtab, key, &datum);
+ if (datum != NULL) {
+ return (struct cil_name *)datum;
+ }
+
+ if (parent->flavor == CIL_CALL) {
+ struct cil_call *call = parent->data;
+ macro = call->macro;
+ } else if (parent->flavor == CIL_MACRO) {
+ macro = parent->data;
+ }
+ if (macro != NULL) {
+ struct cil_list_item *item;
+ cil_list_for_each(item, macro->params) {
+ if (((struct cil_param*)item->data)->str == key) {
+ return NULL;
+ }
+ }
+ }
+
+ cil_name_init(&name);
+ cil_symtab_insert(symtab, key, (struct cil_symtab_datum *)name, ast_node);
+ cil_list_append(db->names, CIL_NAME, name);
+
+ return name;
+}
+
+static int __cil_resolve_perms(symtab_t *class_symtab, symtab_t *common_symtab, struct cil_list *perm_strs, struct cil_list **perm_datums)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_init(perm_datums, perm_strs->flavor);
+
+ cil_list_for_each(curr, perm_strs) {
+ if (curr->flavor == CIL_LIST) {
+ struct cil_list *sub_list;
+ rc = __cil_resolve_perms(class_symtab, common_symtab, curr->data, &sub_list);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve permission list\n");
+ goto exit;
+ }
+ cil_list_append(*perm_datums, CIL_LIST, sub_list);
+ } else if (curr->flavor == CIL_STRING) {
+ struct cil_symtab_datum *perm_datum = NULL;
+ rc = cil_symtab_get_datum(class_symtab, curr->data, &perm_datum);
+ if (rc == SEPOL_ENOENT) {
+ if (common_symtab) {
+ rc = cil_symtab_get_datum(common_symtab, curr->data, &perm_datum);
+ }
+ }
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve permission %s\n", (char*)curr->data);
+ goto exit;
+ }
+ cil_list_append(*perm_datums, CIL_DATUM, perm_datum);
+ } else {
+ cil_list_append(*perm_datums, curr->flavor, curr->data);
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_classperms(struct cil_tree_node *current, struct cil_classperms *cp, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_symtab_datum *datum = NULL;
+ symtab_t *common_symtab = NULL;
+ struct cil_class *class;
+
+ rc = cil_resolve_name(current, cp->class_str, CIL_SYM_CLASSES, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ class = (struct cil_class *)datum;
+
+ if (class->common != NULL) {
+ common_symtab = &class->common->perms;
+ }
+
+ cp->class = class;
+
+ rc = __cil_resolve_perms(&class->perms, common_symtab, cp->perm_strs, &cp->perms);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_classperms_set(struct cil_tree_node *current, struct cil_classperms_set *cp_set, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_symtab_datum *datum = NULL;
+
+ rc = cil_resolve_name(current, cp_set->set_str, CIL_SYM_CLASSPERMSETS, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cp_set->set = (struct cil_classpermission*)datum;
+
+ /* This could be an anonymous classpermission */
+ if (datum->name == NULL) {
+ rc = cil_resolve_classperms_list(current, cp_set->set->classperms, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_classperms_list(struct cil_tree_node *current, struct cil_list *cp_list, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, cp_list) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ rc = cil_resolve_classperms(current, curr->data, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else {
+ rc = cil_resolve_classperms_set(current, curr->data, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_classpermissionset(struct cil_tree_node *current, struct cil_classpermissionset *cps, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list_item *curr;
+ struct cil_symtab_datum *datum;
+ struct cil_classpermission *cp;
+
+ rc = cil_resolve_name(current, cps->set_str, CIL_SYM_CLASSPERMSETS, args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_classperms_list(current, cps->classperms, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ cp = (struct cil_classpermission *)datum;
+
+ if (cp->classperms == NULL) {
+ cil_list_init(&cp->classperms, CIL_CLASSPERMS);
+ }
+
+ cil_list_for_each(curr, cps->classperms) {
+ cil_list_append(cp->classperms, curr->flavor, curr->data);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_type_used(struct cil_symtab_datum *datum)
+{
+ struct cil_typeattribute *attr = NULL;
+
+ if (FLAVOR(datum) == CIL_TYPEATTRIBUTE) {
+ attr = (struct cil_typeattribute*)datum;
+ attr->used = CIL_TRUE;
+ }
+
+ return 0;
+}
+
+int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args)
+{
+ struct cil_symtab_datum *obj_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, permx->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ permx->obj = (struct cil_class*)obj_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_avrule(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = NULL;
+
+ struct cil_avrule *rule = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *tgt_datum = NULL;
+ struct cil_symtab_datum *permx_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (args != NULL) {
+ db = args->db;
+ }
+
+ rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->src = src_datum;
+ if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+ cil_type_used(src_datum);
+ }
+
+ if (rule->tgt_str == CIL_KEY_SELF) {
+ rule->tgt = db->selftype;
+ } else {
+ rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, args, &tgt_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->tgt = tgt_datum;
+ if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) {
+ cil_type_used(tgt_datum);
+ }
+ }
+
+ if (!rule->is_extended) {
+ rc = cil_resolve_classperms_list(current, rule->perms.classperms, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else {
+ if (rule->perms.x.permx_str != NULL) {
+ rc = cil_resolve_name(current, rule->perms.x.permx_str, CIL_SYM_PERMX, args, &permx_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->perms.x.permx = (struct cil_permissionx*)permx_datum;
+ } else {
+ rc = cil_resolve_permissionx(current, rule->perms.x.permx, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_type_rule *rule = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *tgt_datum = NULL;
+ struct cil_symtab_datum *obj_datum = NULL;
+ struct cil_symtab_datum *result_datum = NULL;
+ struct cil_tree_node *result_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->src = src_datum;
+ cil_type_used(src_datum);
+
+ rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->tgt = tgt_datum;
+ cil_type_used(tgt_datum);
+
+ rc = cil_resolve_name(current, rule->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rule->obj = (struct cil_class*)obj_datum;
+
+ rc = cil_resolve_name(current, rule->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ result_node = result_datum->nodes->head->data;
+
+ if (result_node->flavor != CIL_TYPE) {
+ cil_log(CIL_ERR, "Type rule result must be a type [%d]\n",result_node->flavor);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ rule->result = result_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_typeattributeset *attrtypes = current->data;
+ struct cil_symtab_datum *attr_datum = NULL;
+ struct cil_tree_node *attr_node = NULL;
+ struct cil_typeattribute *attr = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, attrtypes->attr_str, CIL_SYM_TYPES, extra_args, &attr_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ attr_node = attr_datum->nodes->head->data;
+
+ if (attr_node->flavor != CIL_TYPEATTRIBUTE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Attribute type not an attribute\n");
+ goto exit;
+ }
+
+ attr = (struct cil_typeattribute*)attr_datum;
+
+ rc = cil_resolve_expr(CIL_TYPEATTRIBUTESET, attrtypes->str_expr, &attrtypes->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_verify_no_self_reference(attr_datum, attrtypes->datum_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (attr->expr_list == NULL) {
+ cil_list_init(&attr->expr_list, CIL_TYPEATTRIBUTE);
+ }
+
+ cil_list_append(attr->expr_list, CIL_LIST, attrtypes->datum_expr);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor)
+{
+ int rc = SEPOL_ERR;
+ enum cil_sym_index sym_index;
+ struct cil_aliasactual *aliasactual = current->data;
+ struct cil_symtab_datum *alias_datum = NULL;
+ struct cil_symtab_datum *actual_datum = NULL;
+ struct cil_alias *alias;
+
+ rc = cil_flavor_to_symtab_index(flavor, &sym_index);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rc = cil_resolve_name(current, aliasactual->alias_str, sym_index, extra_args, &alias_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_name(current, aliasactual->actual_str, sym_index, extra_args, &actual_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ alias = (struct cil_alias *)alias_datum;
+
+ if (alias->actual != NULL) {
+ cil_log(CIL_ERR, "Alias cannot bind more than one value\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ alias->actual = actual_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor flavor)
+{
+ struct cil_alias *alias = current->data;
+ struct cil_alias *a1 = current->data;
+ struct cil_alias *a2 = current->data;
+ struct cil_tree_node *a1_node = NULL;
+ int steps = 0;
+ int limit = 2;
+
+ if (alias->actual == NULL) {
+ cil_tree_log(current, CIL_ERR, "Alias declared but not used");
+ return SEPOL_ERR;
+ }
+
+ a1_node = a1->datum.nodes->head->data;
+
+ while (flavor != a1_node->flavor) {
+ a1 = a1->actual;
+ a1_node = a1->datum.nodes->head->data;
+ steps += 1;
+
+ if (a1 == a2) {
+ cil_log(CIL_ERR, "Circular alias found: %s ", a1->datum.name);
+ a1 = a1->actual;
+ while (a1 != a2) {
+ cil_log(CIL_ERR, "%s ", a1->datum.name);
+ a1 = a1->actual;
+ }
+ cil_log(CIL_ERR,"\n");
+ return SEPOL_ERR;
+ }
+
+ if (steps == limit) {
+ steps = 0;
+ limit *= 2;
+ a2 = a1;
+ }
+ }
+
+ alias->actual = a1;
+
+ return SEPOL_OK;
+}
+
+int cil_resolve_typepermissive(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_typepermissive *typeperm = current->data;
+ struct cil_symtab_datum *type_datum = NULL;
+ struct cil_tree_node *type_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, typeperm->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ type_node = type_datum->nodes->head->data;
+
+ if (type_node->flavor != CIL_TYPE && type_node->flavor != CIL_TYPEALIAS) {
+ cil_log(CIL_ERR, "Typepermissive must be a type or type alias\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ typeperm->type = type_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_nametypetransition *nametypetrans = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *tgt_datum = NULL;
+ struct cil_symtab_datum *obj_datum = NULL;
+ struct cil_symtab_datum *name_datum = NULL;
+ struct cil_symtab_datum *result_datum = NULL;
+ struct cil_tree_node *result_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, nametypetrans->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nametypetrans->src = src_datum;
+ cil_type_used(src_datum);
+
+ rc = cil_resolve_name(current, nametypetrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nametypetrans->tgt = tgt_datum;
+ cil_type_used(tgt_datum);
+
+ rc = cil_resolve_name(current, nametypetrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nametypetrans->obj = (struct cil_class*)obj_datum;
+
+ nametypetrans->name = __cil_insert_name(args->db, nametypetrans->name_str, current);
+ if (nametypetrans->name == NULL) {
+ rc = cil_resolve_name(current, nametypetrans->name_str, CIL_SYM_NAMES, extra_args, &name_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nametypetrans->name = (struct cil_name *)name_datum;
+ }
+
+ rc = cil_resolve_name(current, nametypetrans->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ result_node = result_datum->nodes->head->data;
+
+ if (result_node->flavor != CIL_TYPE && result_node->flavor != CIL_TYPEALIAS) {
+ cil_log(CIL_ERR, "typetransition result is not a type or type alias\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ nametypetrans->result = result_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_rangetransition(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_rangetransition *rangetrans = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *exec_datum = NULL;
+ struct cil_symtab_datum *obj_datum = NULL;
+ struct cil_symtab_datum *range_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, rangetrans->src_str, CIL_SYM_TYPES, extra_args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rangetrans->src = src_datum;
+ cil_type_used(src_datum);
+
+ rc = cil_resolve_name(current, rangetrans->exec_str, CIL_SYM_TYPES, extra_args, &exec_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rangetrans->exec = exec_datum;
+ cil_type_used(exec_datum);
+
+ rc = cil_resolve_name(current, rangetrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rangetrans->obj = (struct cil_class*)obj_datum;
+
+ if (rangetrans->range_str != NULL) {
+ rc = cil_resolve_name(current, rangetrans->range_str, CIL_SYM_LEVELRANGES, extra_args, &range_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ rangetrans->range = (struct cil_levelrange*)range_datum;
+
+ /* This could still be an anonymous levelrange even if range_str is set, if range_str is a param_str*/
+ if (rangetrans->range->datum.name == NULL) {
+ rc = cil_resolve_levelrange(current, rangetrans->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ rc = cil_resolve_levelrange(current, rangetrans->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __class_update_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ struct cil_perm *perm = (struct cil_perm *)d;
+
+ perm->value += *((int *)args);
+
+ return SEPOL_OK;
+}
+
+int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_class *class = NULL;
+ struct cil_class *common = NULL;
+ struct cil_classcommon *clscom = current->data;
+ struct cil_symtab_datum *class_datum = NULL;
+ struct cil_symtab_datum *common_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, clscom->class_str, CIL_SYM_CLASSES, extra_args, &class_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_name(current, clscom->common_str, CIL_SYM_COMMONS, extra_args, &common_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ class = (struct cil_class *)class_datum;
+ common = (struct cil_class *)common_datum;
+ if (class->common != NULL) {
+ cil_log(CIL_ERR, "class cannot be associeated with more than one common\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ class->common = common;
+
+ cil_symtab_map(&class->perms, __class_update_perm_values, &common->num_perms);
+
+ class->num_perms += common->num_perms;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_classmapping(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_classmapping *mapping = current->data;
+ struct cil_class *map = NULL;
+ struct cil_perm *mp = NULL;
+ struct cil_symtab_datum *datum = NULL;
+ struct cil_list_item *curr;
+
+ rc = cil_resolve_name(current, mapping->map_class_str, CIL_SYM_CLASSES, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ map = (struct cil_class*)datum;
+
+ rc = cil_symtab_get_datum(&map->perms, mapping->map_perm_str, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ mp = (struct cil_perm*)datum;
+
+ rc = cil_resolve_classperms_list(current, mapping->classperms, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (mp->classperms == NULL) {
+ cil_list_init(&mp->classperms, CIL_CLASSPERMS);
+ }
+
+ cil_list_for_each(curr, mapping->classperms) {
+ cil_list_append(mp->classperms, curr->flavor, curr->data);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_userrole(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_userrole *userrole = current->data;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *role_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, userrole->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ userrole->user = (struct cil_user*)user_datum;
+
+ rc = cil_resolve_name(current, userrole->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ userrole->role = role_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_userlevel *usrlvl = current->data;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *lvl_datum = NULL;
+ struct cil_user *user = NULL;
+ struct cil_tree_node *user_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, usrlvl->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ user_node = user_datum->nodes->head->data;
+
+ if (user_node->flavor != CIL_USER) {
+ cil_log(CIL_ERR, "Userlevel must be a user\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ user = (struct cil_user*)user_datum;
+
+ if (usrlvl->level_str != NULL) {
+ rc = cil_resolve_name(current, usrlvl->level_str, CIL_SYM_LEVELS, extra_args, &lvl_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ usrlvl->level = (struct cil_level*)lvl_datum;
+ user->dftlevel = usrlvl->level;
+
+ /* This could still be an anonymous level even if level_str is set, if level_str is a param_str*/
+ if (user->dftlevel->datum.name == NULL) {
+ rc = cil_resolve_level(current, user->dftlevel, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (usrlvl->level != NULL) {
+ rc = cil_resolve_level(current, usrlvl->level, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ user->dftlevel = usrlvl->level;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_userrange *userrange = current->data;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *range_datum = NULL;
+ struct cil_user *user = NULL;
+ struct cil_tree_node *user_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, userrange->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ user_node = user_datum->nodes->head->data;
+
+ if (user_node->flavor != CIL_USER) {
+ cil_log(CIL_ERR, "Userrange must be a user: %s\n", user_datum->fqn);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ user = (struct cil_user*)user_datum;
+
+ if (userrange->range_str != NULL) {
+ rc = cil_resolve_name(current, userrange->range_str, CIL_SYM_LEVELRANGES, extra_args, &range_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ userrange->range = (struct cil_levelrange*)range_datum;
+ user->range = userrange->range;
+
+ /* This could still be an anonymous levelrange even if levelrange_str is set, if levelrange_str is a param_str*/
+ if (user->range->datum.name == NULL) {
+ rc = cil_resolve_levelrange(current, user->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (userrange->range != NULL) {
+ rc = cil_resolve_levelrange(current, userrange->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ user->range = userrange->range;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_userprefix *userprefix = current->data;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_tree_node *user_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, userprefix->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ user_node = user_datum->nodes->head->data;
+
+ if (user_node->flavor != CIL_USER) {
+ cil_log(CIL_ERR, "Userprefix must be a user: %s\n", user_datum->fqn);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ userprefix->user = (struct cil_user*)user_datum;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_selinuxuser *selinuxuser = current->data;
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *lvlrange_datum = NULL;
+ struct cil_tree_node *user_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, selinuxuser->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ user_node = user_datum->nodes->head->data;
+
+ if (user_node->flavor != CIL_USER) {
+ cil_log(CIL_ERR, "Selinuxuser must be a user: %s\n", user_datum->fqn);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ selinuxuser->user = (struct cil_user*)user_datum;
+
+ if (selinuxuser->range_str != NULL) {
+ rc = cil_resolve_name(current, selinuxuser->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ selinuxuser->range = (struct cil_levelrange*)lvlrange_datum;
+
+ /* This could still be an anonymous levelrange even if range_str is set, if range_str is a param_str*/
+ if (selinuxuser->range->datum.name == NULL) {
+ rc = cil_resolve_levelrange(current, selinuxuser->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (selinuxuser->range != NULL) {
+ rc = cil_resolve_levelrange(current, selinuxuser->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+}
+
+int cil_resolve_roletype(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_roletype *roletype = current->data;
+ struct cil_symtab_datum *role_datum = NULL;
+ struct cil_symtab_datum *type_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, roletype->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roletype->role = (struct cil_role*)role_datum;
+
+ rc = cil_resolve_name(current, roletype->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roletype->type = (struct cil_type*)type_datum;
+ cil_type_used(type_datum);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_roletransition *roletrans = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *tgt_datum = NULL;
+ struct cil_symtab_datum *obj_datum = NULL;
+ struct cil_symtab_datum *result_datum = NULL;
+ struct cil_tree_node *node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, roletrans->src_str, CIL_SYM_ROLES, extra_args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roletrans->src = (struct cil_role*)src_datum;
+
+ rc = cil_resolve_name(current, roletrans->tgt_str, CIL_SYM_TYPES, extra_args, &tgt_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roletrans->tgt = tgt_datum;
+ cil_type_used(tgt_datum);
+
+ rc = cil_resolve_name(current, roletrans->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roletrans->obj = (struct cil_class*)obj_datum;
+
+ rc = cil_resolve_name(current, roletrans->result_str, CIL_SYM_ROLES, extra_args, &result_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ node = result_datum->nodes->head->data;
+ if (node->flavor != CIL_ROLE) {
+ rc = SEPOL_ERR;
+ printf("%i\n", node->flavor);
+ cil_log(CIL_ERR, "roletransition must result in a role, but %s is a %s\n", roletrans->result_str, cil_node_to_string(node));
+ goto exit;
+ }
+ roletrans->result = (struct cil_role*)result_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_roleallow(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_roleallow *roleallow = current->data;
+ struct cil_symtab_datum *src_datum = NULL;
+ struct cil_symtab_datum *tgt_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, roleallow->src_str, CIL_SYM_ROLES, extra_args, &src_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roleallow->src = (struct cil_role*)src_datum;
+
+ rc = cil_resolve_name(current, roleallow->tgt_str, CIL_SYM_ROLES, extra_args, &tgt_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ roleallow->tgt = (struct cil_role*)tgt_datum;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_roleattributeset *attrroles = current->data;
+ struct cil_symtab_datum *attr_datum = NULL;
+ struct cil_tree_node *attr_node = NULL;
+ struct cil_roleattribute *attr = NULL;
+
+ rc = cil_resolve_name(current, attrroles->attr_str, CIL_SYM_ROLES, extra_args, &attr_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ attr_node = attr_datum->nodes->head->data;
+
+ if (attr_node->flavor != CIL_ROLEATTRIBUTE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Attribute role not an attribute\n");
+ goto exit;
+ }
+ attr = (struct cil_roleattribute*)attr_datum;
+
+ rc = cil_resolve_expr(CIL_ROLEATTRIBUTESET, attrroles->str_expr, &attrroles->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_verify_no_self_reference(attr_datum, attrroles->datum_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (attr->expr_list == NULL) {
+ cil_list_init(&attr->expr_list, CIL_ROLEATTRIBUTE);
+ }
+
+ cil_list_append(attr->expr_list, CIL_LIST, attrroles->datum_expr);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+struct cil_ordered_list {
+ int merged;
+ struct cil_list *list;
+ struct cil_tree_node *node;
+};
+
+void __cil_ordered_list_init(struct cil_ordered_list **ordered)
+{
+ *ordered = cil_malloc(sizeof(**ordered));
+
+ (*ordered)->merged = CIL_FALSE;
+ (*ordered)->list = NULL;
+ (*ordered)->node = NULL;
+}
+
+void __cil_ordered_list_destroy(struct cil_ordered_list **ordered)
+{
+ cil_list_destroy(&(*ordered)->list, CIL_FALSE);
+ (*ordered)->node = NULL;
+ free(*ordered);
+ *ordered = NULL;
+}
+
+void __cil_ordered_lists_destroy(struct cil_list **ordered_lists)
+{
+ struct cil_list_item *item = NULL;
+
+ if (ordered_lists == NULL || *ordered_lists == NULL) {
+ return;
+ }
+
+ item = (*ordered_lists)->head;
+ while (item != NULL) {
+ struct cil_list_item *next = item->next;
+ struct cil_ordered_list *ordered = item->data;
+ __cil_ordered_list_destroy(&ordered);
+ free(item);
+ item = next;
+ }
+ free(*ordered_lists);
+ *ordered_lists = NULL;
+}
+
+void __cil_ordered_lists_reset(struct cil_list **ordered_lists)
+{
+ __cil_ordered_lists_destroy(ordered_lists);
+ cil_list_init(ordered_lists, CIL_LIST_ITEM);
+}
+
+struct cil_list_item *__cil_ordered_item_insert(struct cil_list *old, struct cil_list_item *curr, struct cil_list_item *item)
+{
+ if (item->flavor == CIL_SID) {
+ struct cil_sid *sid = item->data;
+ if (sid->ordered == CIL_TRUE) {
+ cil_log(CIL_ERR, "SID %s has already been merged into the ordered list\n", sid->datum.name);
+ return NULL;
+ }
+ sid->ordered = CIL_TRUE;
+ } else if (item->flavor == CIL_CLASS) {
+ struct cil_class *class = item->data;
+ if (class->ordered == CIL_TRUE) {
+ cil_log(CIL_ERR, "Class %s has already been merged into the ordered list\n", class->datum.name);
+ return NULL;
+ }
+ class->ordered = CIL_TRUE;
+ } else if (item->flavor == CIL_CAT) {
+ struct cil_cat *cat = item->data;
+ if (cat->ordered == CIL_TRUE) {
+ cil_log(CIL_ERR, "Category %s has already been merged into the ordered list\n", cat->datum.name);
+ return NULL;
+ }
+ cat->ordered = CIL_TRUE;
+ } else if (item->flavor == CIL_SENS) {
+ struct cil_sens *sens = item->data;
+ if (sens->ordered == CIL_TRUE) {
+ cil_log(CIL_ERR, "Sensitivity %s has already been merged into the ordered list\n", sens->datum.name);
+ return NULL;
+ }
+ sens->ordered = CIL_TRUE;
+ }
+
+ return cil_list_insert(old, curr, item->flavor, item->data);
+}
+
+int __cil_ordered_list_insert(struct cil_list *old, struct cil_list_item *ocurr, struct cil_list_item *nstart, struct cil_list_item *nstop)
+{
+ struct cil_list_item *ncurr = NULL;
+
+ for (ncurr = nstart; ncurr != nstop; ncurr = ncurr->next) {
+ ocurr = __cil_ordered_item_insert(old, ocurr, ncurr);
+ if (ocurr == NULL) {
+ return SEPOL_ERR;
+ }
+ }
+ return SEPOL_OK;
+}
+
+struct cil_list_item *__cil_ordered_find_match(struct cil_list_item *t, struct cil_list_item *i)
+{
+ while (i) {
+ if (i->data == t->data) {
+ return i;
+ }
+ i = i->next;
+ }
+ return NULL;
+}
+
+int __cil_ordered_lists_merge(struct cil_list *old, struct cil_list *new)
+{
+ struct cil_list_item *omatch = NULL;
+ struct cil_list_item *ofirst = old->head;
+ struct cil_list_item *ocurr = NULL;
+ struct cil_list_item *oprev = NULL;
+ struct cil_list_item *nmatch = NULL;
+ struct cil_list_item *nfirst = new->head;
+ struct cil_list_item *ncurr = NULL;
+ int rc = SEPOL_ERR;
+
+ if (nfirst == NULL) {
+ return SEPOL_OK;
+ }
+
+ if (ofirst == NULL) {
+ /* First list added */
+ rc = __cil_ordered_list_insert(old, NULL, nfirst, NULL);
+ return rc;
+ }
+
+ /* Find a match between the new list and the old one */
+ for (nmatch = nfirst; nmatch; nmatch = nmatch->next) {
+ omatch = __cil_ordered_find_match(nmatch, ofirst);
+ if (omatch) {
+ break;
+ }
+ }
+
+ if (!nmatch) {
+ /* List cannot be merged yet */
+ return SEPOL_ERR;
+ }
+
+ if (nmatch != nfirst && omatch != ofirst) {
+ /* Potential ordering conflict--try again later */
+ return SEPOL_ERR;
+ }
+
+ if (nmatch != nfirst) {
+ /* Prepend the beginning of the new list up to the first match to the old list */
+ rc = __cil_ordered_list_insert(old, NULL, nfirst, nmatch);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ }
+
+ /* In the overlapping protion, add items from the new list not in the old list */
+ ncurr = nmatch->next;
+ ocurr = omatch->next;
+ oprev = omatch;
+ while (ncurr && ocurr) {
+ if (ncurr->data == ocurr->data) {
+ oprev = ocurr;
+ ocurr = ocurr->next;
+ ncurr = ncurr->next;
+ } else {
+ /* Handle gap in old: old = (A C) new = (A B C) */
+ nmatch = __cil_ordered_find_match(ocurr, ncurr->next);
+ if (nmatch) {
+ rc = __cil_ordered_list_insert(old, oprev, ncurr, nmatch);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ oprev = ocurr;
+ ocurr = ocurr->next;
+ ncurr = nmatch->next;
+ continue;
+ }
+ /* Handle gap in new: old = (A B C) new = (A C) */
+ omatch = __cil_ordered_find_match(ncurr, ocurr->next);
+ if (omatch) {
+ /* Nothing to insert, just skip */
+ oprev = omatch;
+ ocurr = omatch->next;
+ ncurr = ncurr->next;
+ continue;
+ } else {
+ return SEPOL_ERR;
+ }
+ }
+ }
+
+ if (ncurr) {
+ /* Add the rest of the items from the new list */
+ rc = __cil_ordered_list_insert(old, old->tail, ncurr, NULL);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+static int insert_unordered(struct cil_list *merged, struct cil_list *unordered)
+{
+ struct cil_list_item *curr = NULL;
+ struct cil_ordered_list *unordered_list = NULL;
+ struct cil_list_item *item = NULL;
+ struct cil_list_item *ret = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_list_for_each(curr, unordered) {
+ unordered_list = curr->data;
+
+ cil_list_for_each(item, unordered_list->list) {
+ if (cil_list_contains(merged, item->data)) {
+ /* item was declared in an ordered statement, which supercedes
+ * all unordered statements */
+ if (item->flavor == CIL_CLASS) {
+ cil_log(CIL_WARN, "Ignoring '%s' as it has already been declared in classorder.\n", ((struct cil_class*)(item->data))->datum.name);
+ }
+ continue;
+ }
+
+ ret = __cil_ordered_item_insert(merged, merged->tail, item);
+ if (ret == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+struct cil_list *__cil_ordered_lists_merge_all(struct cil_list **ordered_lists, struct cil_list **unordered_lists)
+{
+ struct cil_list *composite = NULL;
+ struct cil_list_item *curr = NULL;
+ int changed = CIL_TRUE;
+ int waiting = 1;
+ int rc = SEPOL_ERR;
+
+ cil_list_init(&composite, CIL_LIST_ITEM);
+
+ while (waiting && changed == CIL_TRUE) {
+ changed = CIL_FALSE;
+ waiting = 0;
+ cil_list_for_each(curr, *ordered_lists) {
+ struct cil_ordered_list *ordered_list = curr->data;
+ if (ordered_list->merged == CIL_FALSE) {
+ rc = __cil_ordered_lists_merge(composite, ordered_list->list);
+ if (rc != SEPOL_OK) {
+ /* Can't merge yet */
+ waiting++;
+ } else {
+ ordered_list->merged = CIL_TRUE;
+ changed = CIL_TRUE;
+ }
+ }
+ }
+ if (waiting > 0 && changed == CIL_FALSE) {
+ cil_list_for_each(curr, *ordered_lists) {
+ struct cil_ordered_list *ordered_list = curr->data;
+ if (ordered_list->merged == CIL_FALSE) {
+ cil_tree_log(ordered_list->node, CIL_ERR, "Unable to merge ordered list");
+ }
+ }
+ goto exit;
+ }
+ }
+
+ if (unordered_lists != NULL) {
+ rc = insert_unordered(composite, *unordered_lists);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ __cil_ordered_lists_destroy(ordered_lists);
+ __cil_ordered_lists_destroy(unordered_lists);
+
+ return composite;
+
+exit:
+ __cil_ordered_lists_destroy(ordered_lists);
+ __cil_ordered_lists_destroy(unordered_lists);
+ cil_list_destroy(&composite, CIL_FALSE);
+ return NULL;
+}
+
+int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list *classorder_list = args->classorder_lists;
+ struct cil_list *unordered_classorder_list = args->unordered_classorder_lists;
+ struct cil_classorder *classorder = current->data;
+ struct cil_list *new = NULL;
+ struct cil_list_item *curr = NULL;
+ struct cil_symtab_datum *datum = NULL;
+ struct cil_ordered_list *class_list = NULL;
+ int rc = SEPOL_ERR;
+ int unordered = CIL_FALSE;
+
+ cil_list_init(&new, CIL_CLASSORDER);
+
+ cil_list_for_each(curr, classorder->class_list_str) {
+ if (curr->data == CIL_KEY_UNORDERED) {
+ unordered = CIL_TRUE;
+ continue;
+ }
+
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve class %s in classorder\n", (char *)curr->data);
+ goto exit;
+ }
+ cil_list_append(new, CIL_CLASS, datum);
+ }
+
+ __cil_ordered_list_init(&class_list);
+ class_list->list = new;
+ class_list->node = current;
+ if (unordered) {
+ cil_list_append(unordered_classorder_list, CIL_CLASSORDER, class_list);
+ } else {
+ cil_list_append(classorder_list, CIL_CLASSORDER, class_list);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list *sidorder_list = args->sidorder_lists;
+ struct cil_sidorder *sidorder = current->data;
+ struct cil_list *new = NULL;
+ struct cil_list_item *curr = NULL;
+ struct cil_symtab_datum *datum = NULL;
+ struct cil_ordered_list *ordered = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_list_init(&new, CIL_SIDORDER);
+
+ cil_list_for_each(curr, sidorder->sid_list_str) {
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SIDS, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve sid %s in sidorder\n", (char *)curr->data);
+ goto exit;
+ }
+ cil_list_append(new, CIL_SID, datum);
+ }
+
+ __cil_ordered_list_init(&ordered);
+ ordered->list = new;
+ ordered->node = current;
+ cil_list_append(sidorder_list, CIL_SIDORDER, ordered);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+void cil_set_cat_values(struct cil_list *ordered_cats, struct cil_db *db)
+{
+ struct cil_list_item *curr;
+ int v = 0;
+
+ cil_list_for_each(curr, ordered_cats) {
+ struct cil_cat *cat = curr->data;
+ cat->value = v;
+ v++;
+ }
+
+ db->num_cats = v;
+}
+
+int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list *catorder_list = args->catorder_lists;
+ struct cil_catorder *catorder = current->data;
+ struct cil_list *new = NULL;
+ struct cil_list_item *curr = NULL;
+ struct cil_symtab_datum *cat_datum;
+ struct cil_cat *cat = NULL;
+ struct cil_ordered_list *ordered = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_list_init(&new, CIL_CATORDER);
+
+ cil_list_for_each(curr, catorder->cat_list_str) {
+ struct cil_tree_node *node = NULL;
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CATS, extra_args, &cat_datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve category %s in categoryorder\n", (char *)curr->data);
+ goto exit;
+ }
+ node = cat_datum->nodes->head->data;
+ if (node->flavor != CIL_CAT) {
+ cil_log(CIL_ERR, "%s is not a category. Only categories are allowed in categoryorder statements\n", cat_datum->name);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ cat = (struct cil_cat *)cat_datum;
+ cil_list_append(new, CIL_CAT, cat);
+ }
+
+ __cil_ordered_list_init(&ordered);
+ ordered->list = new;
+ ordered->node = current;
+ cil_list_append(catorder_list, CIL_CATORDER, ordered);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list *sensitivityorder_list = args->sensitivityorder_lists;
+ struct cil_sensorder *sensorder = current->data;
+ struct cil_list *new = NULL;
+ struct cil_list_item *curr = NULL;
+ struct cil_symtab_datum *datum = NULL;
+ struct cil_ordered_list *ordered = NULL;
+ int rc = SEPOL_ERR;
+
+ cil_list_init(&new, CIL_LIST_ITEM);
+
+ cil_list_for_each(curr, sensorder->sens_list_str) {
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SENS, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to resolve sensitivty %s in sensitivityorder\n", (char *)curr->data);
+ goto exit;
+ }
+ cil_list_append(new, CIL_SENS, datum);
+ }
+
+ __cil_ordered_list_init(&ordered);
+ ordered->list = new;
+ ordered->node = current;
+ cil_list_append(sensitivityorder_list, CIL_SENSITIVITYORDER, ordered);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_cats(struct cil_tree_node *current, struct cil_cats *cats, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_expr(CIL_CATSET, cats->str_expr, &cats->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_cats(current, catset->cats, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_verify_no_self_reference((struct cil_symtab_datum *)catset, catset->cats->datum_expr);
+ if (rc != SEPOL_OK) {
+ cil_list_destroy(&catset->cats->datum_expr, CIL_FALSE);
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+int cil_resolve_senscat(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_senscat *senscat = current->data;
+ struct cil_symtab_datum *sens_datum;
+ struct cil_sens *sens = NULL;
+
+ rc = cil_resolve_name(current, (char*)senscat->sens_str, CIL_SYM_SENS, extra_args, &sens_datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to find sensitivity\n");
+ goto exit;
+ }
+
+ rc = cil_resolve_cats(current, senscat->cats, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ sens = (struct cil_sens *)sens_datum;
+
+ if (sens->cats_list == NULL ) {
+ cil_list_init(&sens->cats_list, CIL_CAT);
+ }
+
+ cil_list_append(sens->cats_list, CIL_CAT, senscat->cats);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_level(struct cil_tree_node *current, struct cil_level *level, void *extra_args)
+{
+ struct cil_symtab_datum *sens_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, (char*)level->sens_str, CIL_SYM_SENS, extra_args, &sens_datum);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to find sensitivity\n");
+ goto exit;
+ }
+
+ level->sens = (struct cil_sens *)sens_datum;
+
+ if (level->cats != NULL) {
+ rc = cil_resolve_cats(current, level->cats, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_levelrange(struct cil_tree_node *current, struct cil_levelrange *lvlrange, void *extra_args)
+{
+ struct cil_symtab_datum *low_datum = NULL;
+ struct cil_symtab_datum *high_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (lvlrange->low_str != NULL) {
+ rc = cil_resolve_name(current, lvlrange->low_str, CIL_SYM_LEVELS, extra_args, &low_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ lvlrange->low = (struct cil_level*)low_datum;
+
+ /* This could still be an anonymous level even if low_str is set, if low_str is a param_str */
+ if (lvlrange->low->datum.name == NULL) {
+ rc = cil_resolve_level(current, lvlrange->low, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (lvlrange->low != NULL) {
+ rc = cil_resolve_level(current, lvlrange->low, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (lvlrange->high_str != NULL) {
+ rc = cil_resolve_name(current, lvlrange->high_str, CIL_SYM_LEVELS, extra_args, &high_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ lvlrange->high = (struct cil_level*)high_datum;
+
+ /* This could still be an anonymous level even if high_str is set, if high_str is a param_str */
+ if (lvlrange->high->datum.name == NULL) {
+ rc = cil_resolve_level(current, lvlrange->high, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (lvlrange->high != NULL) {
+ rc = cil_resolve_level(current, lvlrange->high, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_constrain(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_constrain *cons = current->data;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_classperms_list(current, cons->classperms, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_expr(CIL_CONSTRAIN, cons->str_expr, &cons->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_validatetrans *validtrans = current->data;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_symtab_datum *class_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, validtrans->class_str, CIL_SYM_CLASSES, args, &class_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ validtrans->class = (struct cil_class*)class_datum;
+
+ rc = cil_resolve_expr(CIL_VALIDATETRANS, validtrans->str_expr, &validtrans->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args)
+{
+ struct cil_symtab_datum *user_datum = NULL;
+ struct cil_symtab_datum *role_datum = NULL;
+ struct cil_symtab_datum *type_datum = NULL;
+ struct cil_tree_node *node = NULL;
+ struct cil_symtab_datum *lvlrange_datum = NULL;
+
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, context->user_str, CIL_SYM_USERS, extra_args, &user_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ node = user_datum->nodes->head->data;
+
+ if (node->flavor != CIL_USER) {
+ cil_log(CIL_ERR, "Context user must be a user: %s\n", user_datum->fqn);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ context->user = (struct cil_user*)user_datum;
+
+ rc = cil_resolve_name(current, context->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ node = role_datum->nodes->head->data;
+ if (node->flavor != CIL_ROLE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Context role not a role: %s\n", role_datum->fqn);
+ goto exit;
+ }
+
+ context->role = (struct cil_role*)role_datum;
+
+ rc = cil_resolve_name(current, context->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ node = type_datum->nodes->head->data;
+
+ if (node->flavor != CIL_TYPE && node->flavor != CIL_TYPEALIAS) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Type not a type or type alias\n");
+ goto exit;
+ }
+ context->type = type_datum;
+
+ if (context->range_str != NULL) {
+ rc = cil_resolve_name(current, context->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ context->range = (struct cil_levelrange*)lvlrange_datum;
+
+ /* This could still be an anonymous levelrange even if levelrange_str is set, if levelrange_str is a param_str*/
+ if (context->range->datum.name == NULL) {
+ rc = cil_resolve_levelrange(current, context->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (context->range != NULL) {
+ rc = cil_resolve_levelrange(current, context->range, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_filecon *filecon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (filecon->context_str != NULL) {
+ rc = cil_resolve_name(current, filecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ filecon->context = (struct cil_context*)context_datum;
+ } else if (filecon->context != NULL) {
+ rc = cil_resolve_context(current, filecon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_portcon *portcon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (portcon->context_str != NULL) {
+ rc = cil_resolve_name(current, portcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ portcon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, portcon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_genfscon *genfscon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (genfscon->context_str != NULL) {
+ rc = cil_resolve_name(current, genfscon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ genfscon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, genfscon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_nodecon *nodecon = current->data;
+ struct cil_symtab_datum *addr_datum = NULL;
+ struct cil_symtab_datum *mask_datum = NULL;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (nodecon->addr_str != NULL) {
+ rc = cil_resolve_name(current, nodecon->addr_str, CIL_SYM_IPADDRS, extra_args, &addr_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nodecon->addr = (struct cil_ipaddr*)addr_datum;
+ }
+
+ if (nodecon->mask_str != NULL) {
+ rc = cil_resolve_name(current, nodecon->mask_str, CIL_SYM_IPADDRS, extra_args, &mask_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nodecon->mask = (struct cil_ipaddr*)mask_datum;
+ }
+
+ if (nodecon->context_str != NULL) {
+ rc = cil_resolve_name(current, nodecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ nodecon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, nodecon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (nodecon->addr->family != nodecon->mask->family) {
+ cil_log(CIL_ERR, "Nodecon ip address not in the same family\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_netifcon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_netifcon *netifcon = current->data;
+ struct cil_symtab_datum *ifcon_datum = NULL;
+ struct cil_symtab_datum *packcon_datum = NULL;
+
+ int rc = SEPOL_ERR;
+
+ if (netifcon->if_context_str != NULL) {
+ rc = cil_resolve_name(current, netifcon->if_context_str, CIL_SYM_CONTEXTS, extra_args, &ifcon_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ netifcon->if_context = (struct cil_context*)ifcon_datum;
+ } else {
+ rc = cil_resolve_context(current, netifcon->if_context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (netifcon->packet_context_str != NULL) {
+ rc = cil_resolve_name(current, netifcon->packet_context_str, CIL_SYM_CONTEXTS, extra_args, &packcon_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ netifcon->packet_context = (struct cil_context*)packcon_datum;
+ } else {
+ rc = cil_resolve_context(current, netifcon->packet_context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_pirqcon *pirqcon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (pirqcon->context_str != NULL) {
+ rc = cil_resolve_name(current, pirqcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ pirqcon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, pirqcon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_iomemcon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_iomemcon *iomemcon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (iomemcon->context_str != NULL) {
+ rc = cil_resolve_name(current, iomemcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ iomemcon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, iomemcon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_ioportcon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_ioportcon *ioportcon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (ioportcon->context_str != NULL) {
+ rc = cil_resolve_name(current, ioportcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ ioportcon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, ioportcon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_pcidevicecon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_pcidevicecon *pcidevicecon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (pcidevicecon->context_str != NULL) {
+ rc = cil_resolve_name(current, pcidevicecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ pcidevicecon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, pcidevicecon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_devicetreecon(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_devicetreecon *devicetreecon = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (devicetreecon->context_str != NULL) {
+ rc = cil_resolve_name(current, devicetreecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ devicetreecon->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, devicetreecon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_fsuse(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_fsuse *fsuse = current->data;
+ struct cil_symtab_datum *context_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (fsuse->context_str != NULL) {
+ rc = cil_resolve_name(current, fsuse->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ fsuse->context = (struct cil_context*)context_datum;
+ } else {
+ rc = cil_resolve_context(current, fsuse->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_sidcontext(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_sidcontext *sidcon = current->data;
+ struct cil_symtab_datum *sid_datum = NULL;
+ struct cil_symtab_datum *context_datum = NULL;
+ struct cil_sid *sid = NULL;
+
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, sidcon->sid_str, CIL_SYM_SIDS, extra_args, &sid_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sid = (struct cil_sid*)sid_datum;
+
+ if (sidcon->context_str != NULL) {
+ rc = cil_resolve_name(current, sidcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ sidcon->context = (struct cil_context*)context_datum;
+ } else if (sidcon->context != NULL) {
+ rc = cil_resolve_context(current, sidcon->context, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (sid->context != NULL) {
+ cil_log(CIL_ERR, "sid's cannot be associated with more than one context\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ sid->context = sidcon->context;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_blockinherit *inherit = current->data;
+ struct cil_symtab_datum *block_datum = NULL;
+ struct cil_tree_node *node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ node = block_datum->nodes->head->data;
+
+ if (node->flavor != CIL_BLOCK) {
+ cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node));
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ inherit->block = (struct cil_block *)block_datum;
+
+ if (inherit->block->bi_nodes == NULL) {
+ cil_list_init(&inherit->block->bi_nodes, CIL_NODE);
+ }
+ cil_list_append(inherit->block->bi_nodes, CIL_NODE, current);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node)
+{
+ struct cil_list *trace = NULL;
+ struct cil_list_item *item = NULL;
+ struct cil_tree_node *curr = NULL;
+
+ cil_list_init(&trace, CIL_NODE);
+
+ for (curr = bi_node; curr != terminating_node; curr = curr->parent) {
+ if (curr->flavor == CIL_BLOCK) {
+ cil_list_prepend(trace, CIL_NODE, curr);
+ } else {
+ if (curr != bi_node) {
+ cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block));
+ }
+ cil_list_prepend(trace, CIL_NODE, curr);
+ }
+ }
+ cil_list_prepend(trace, CIL_NODE, terminating_node);
+
+ cil_list_for_each(item, trace) {
+ curr = item->data;
+ if (curr->flavor == CIL_BLOCK) {
+ cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name);
+ } else {
+ cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str);
+ }
+ }
+
+ cil_list_destroy(&trace, CIL_FALSE);
+}
+
+int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node)
+{
+ struct cil_tree_node *curr = NULL;
+ struct cil_blockinherit *bi = NULL;
+ struct cil_block *block = NULL;
+ int rc = SEPOL_ERR;
+
+ bi = bi_node->data;
+
+ for (curr = bi_node->parent; curr != NULL; curr = curr->parent) {
+ if (curr->flavor != CIL_BLOCK) {
+ continue;
+ }
+
+ block = curr->data;
+
+ if (block != bi->block) {
+ continue;
+ }
+
+ cil_log(CIL_ERR, "Recursive blockinherit found:\n");
+ cil_print_recursive_blockinherit(bi_node, curr);
+
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_block *block = current->data;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = NULL;
+ struct cil_list_item *item = NULL;
+ int rc = SEPOL_ERR;
+
+ // This block is not inherited
+ if (block->bi_nodes == NULL) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ db = args->db;
+
+ // Make sure this is the original block and not a merged block from a blockinherit
+ if (current != block->datum.nodes->head->data) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ cil_list_for_each(item, block->bi_nodes) {
+ rc = cil_check_recursive_blockinherit(item->data);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_copy_ast(db, current, item->data);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n");
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_blockabstract *abstract = current->data;
+ struct cil_symtab_datum *block_datum = NULL;
+ struct cil_tree_node *block_node = NULL;
+ int rc = SEPOL_ERR;
+
+ rc = cil_resolve_name(current, abstract->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ block_node = block_datum->nodes->head->data;
+ if (block_node->flavor != CIL_BLOCK) {
+ cil_log(CIL_ERR, "Failed to resolve blockabstract to a block, rc: %d\n", rc);
+ goto exit;
+ }
+
+ ((struct cil_block*)block_datum)->is_abstract = CIL_TRUE;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_in(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_in *in = current->data;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = NULL;
+ struct cil_symtab_datum *block_datum = NULL;
+ struct cil_tree_node *block_node = NULL;
+ int rc = SEPOL_ERR;
+
+ if (args != NULL) {
+ db = args->db;
+ }
+
+ rc = cil_resolve_name(current, in->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ block_node = block_datum->nodes->head->data;
+
+ rc = cil_copy_ast(db, current, block_node);
+ if (rc != SEPOL_OK) {
+ printf("Failed to copy in, rc: %d\n", rc);
+ goto exit;
+ }
+
+ cil_tree_children_destroy(current);
+ current->cl_head = NULL;
+ current->cl_tail = NULL;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_in_list(void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_list *ins = args->in_list;
+ struct cil_list_item *curr = NULL;
+ struct cil_tree_node *node = NULL;
+ struct cil_tree_node *last_failed_node = NULL;
+ struct cil_in *in = NULL;
+ struct cil_symtab_datum *block_datum = NULL;
+ int resolved = 0;
+ int unresolved = 0;
+ int rc = SEPOL_ERR;
+
+ do {
+ resolved = 0;
+ unresolved = 0;
+
+ cil_list_for_each(curr, ins) {
+ if (curr->flavor != CIL_NODE) {
+ continue;
+ }
+
+ node = curr->data;
+ in = node->data;
+
+ rc = cil_resolve_name(node, in->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
+ if (rc != SEPOL_OK) {
+ unresolved++;
+ last_failed_node = node;
+ } else {
+ rc = cil_resolve_in(node, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ resolved++;
+ curr->data = NULL;
+ curr->flavor = CIL_NONE;
+ }
+ }
+
+ if (unresolved > 0 && resolved == 0) {
+ cil_tree_log(last_failed_node, CIL_ERR, "Failed to resolve in-statement");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ } while (unresolved > 0);
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+
+int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor)
+{
+ int rc = SEPOL_ERR;
+ struct cil_bounds *bounds = current->data;
+ enum cil_sym_index index;
+ struct cil_symtab_datum *parent_datum = NULL;
+ struct cil_symtab_datum *child_datum = NULL;
+
+ rc = cil_flavor_to_symtab_index(flavor, &index);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_name(current, bounds->parent_str, index, extra_args, &parent_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_resolve_name(current, bounds->child_str, index, extra_args, &child_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ switch (flavor) {
+ case CIL_USER: {
+ struct cil_user *user = (struct cil_user *)child_datum;
+
+ if (user->bounds != NULL) {
+ struct cil_tree_node *node = user->bounds->datum.nodes->head->data;
+ cil_tree_log(node, CIL_ERR, "User %s already bound by parent", bounds->child_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ user->bounds = (struct cil_user *)parent_datum;
+ break;
+ }
+ case CIL_ROLE: {
+ struct cil_role *role = (struct cil_role *)child_datum;
+
+ if (role->bounds != NULL) {
+ struct cil_tree_node *node = role->bounds->datum.nodes->head->data;
+ cil_tree_log(node, CIL_ERR, "Role %s already bound by parent", bounds->child_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ role->bounds = (struct cil_role *)parent_datum;
+ break;
+ }
+ case CIL_TYPE: {
+ struct cil_type *type = (struct cil_type *)child_datum;
+ struct cil_tree_node *node = NULL;
+
+ if (type->bounds != NULL) {
+ node = ((struct cil_symtab_datum *)type->bounds)->nodes->head->data;
+ cil_tree_log(node, CIL_ERR, "Type %s already bound by parent", bounds->child_str);
+ cil_tree_log(current, CIL_ERR, "Now being bound to parent %s", bounds->parent_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ node = parent_datum->nodes->head->data;
+ if (node->flavor == CIL_TYPEATTRIBUTE) {
+ cil_log(CIL_ERR, "Bounds parent %s is an attribute\n", bounds->parent_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ node = child_datum->nodes->head->data;
+ if (node->flavor == CIL_TYPEATTRIBUTE) {
+ cil_log(CIL_ERR, "Bounds child %s is an attribute\n", bounds->child_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ type->bounds = (struct cil_type *)parent_datum;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(current, CIL_ERR, "Bad bounds statement");
+ return rc;
+}
+
+int cil_resolve_default(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_default *def = current->data;
+ struct cil_list_item *curr;
+ struct cil_symtab_datum *datum;
+
+ cil_list_init(&def->class_datums, def->flavor);
+
+ cil_list_for_each(curr, def->class_strs) {
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_append(def->class_datums, CIL_CLASS, datum);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_defaultrange(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_defaultrange *def = current->data;
+ struct cil_list_item *curr;
+ struct cil_symtab_datum *datum;
+
+ cil_list_init(&def->class_datums, CIL_DEFAULTRANGE);
+
+ cil_list_for_each(curr, def->class_strs) {
+ rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_append(def->class_datums, CIL_CLASS, datum);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *terminating_node)
+{
+ struct cil_list *trace = NULL;
+ struct cil_list_item * item = NULL;
+ struct cil_tree_node *curr = NULL;
+
+ cil_list_init(&trace, CIL_NODE);
+
+ for (curr = call_node; curr != terminating_node; curr = curr->parent) {
+ if (curr->flavor == CIL_CALL) {
+ if (curr != call_node) {
+ cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)curr->data)->macro));
+ }
+ cil_list_prepend(trace, CIL_NODE, curr);
+ }
+ }
+
+ if (terminating_node->flavor == CIL_MACRO) {
+ cil_list_prepend(trace, CIL_NODE, terminating_node);
+ } else {
+ cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)terminating_node->data)->macro));
+ }
+
+ cil_list_for_each(item, trace) {
+ curr = item->data;
+ if (curr->flavor == CIL_MACRO) {
+ cil_tree_log(curr, CIL_ERR, "macro %s", DATUM(curr->data)->name);
+ } else {
+ cil_tree_log(curr, CIL_ERR, "call %s", ((struct cil_call *)curr->data)->macro_str);
+ }
+ }
+
+ cil_list_destroy(&trace, CIL_FALSE);
+}
+
+int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node)
+{
+ struct cil_tree_node *curr = NULL;
+ struct cil_call * call = NULL;
+ int rc = SEPOL_ERR;
+
+ for (curr = call_node; curr != NULL; curr = curr->parent) {
+ if (curr->flavor == CIL_CALL) {
+ if (curr == call_node) {
+ continue;
+ }
+
+ call = curr->data;
+ if (call->macro != macro_node->data) {
+ continue;
+ }
+ } else if (curr->flavor == CIL_MACRO) {
+ if (curr != macro_node) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ } else {
+ continue;
+ }
+
+ cil_log(CIL_ERR, "Recursive macro call found:\n");
+ cil_print_recursive_call(call_node, curr);
+
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+}
+
+int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_call *new_call = current->data;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = NULL;
+ struct cil_tree_node *macro_node = NULL;
+ struct cil_symtab_datum *macro_datum = NULL;
+ int rc = SEPOL_ERR;
+
+ if (args != NULL) {
+ db = args->db;
+ }
+
+ rc = cil_resolve_name(current, new_call->macro_str, CIL_SYM_BLOCKS, extra_args, ¯o_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ macro_node = macro_datum->nodes->head->data;
+
+ if (macro_node->flavor != CIL_MACRO) {
+ printf("Failed to resolve %s to a macro\n", new_call->macro_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ new_call->macro = (struct cil_macro*)macro_datum;
+
+ if (new_call->macro->params != NULL ) {
+
+ struct cil_list_item *item;
+ struct cil_args *new_arg = NULL;
+ struct cil_tree_node *pc = NULL;
+
+ if (new_call->args_tree == NULL) {
+ cil_tree_log(current, CIL_ERR, "Missing arguments");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ pc = new_call->args_tree->root->cl_head;
+
+ cil_list_init(&new_call->args, CIL_LIST_ITEM);
+
+ cil_list_for_each(item, new_call->macro->params) {
+ enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor;
+
+ if (pc == NULL) {
+ cil_tree_log(current, CIL_ERR, "Missing arguments");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ if (item->flavor != CIL_PARAM) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_args_init(&new_arg);
+
+ switch (flavor) {
+ case CIL_NAME: {
+ struct cil_name *name;
+ name = __cil_insert_name(args->db, pc->data, current);
+ if (name != NULL) {
+ new_arg->arg = (struct cil_symtab_datum *)name;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+ }
+ break;
+ case CIL_TYPE:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_ROLE:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_USER:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_SENS:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_CAT:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_BOOL:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_CATSET: {
+ if (pc->cl_head != NULL) {
+ struct cil_catset *catset = NULL;
+ struct cil_tree_node *cat_node = NULL;
+ cil_catset_init(&catset);
+ rc = cil_fill_cats(pc, &catset->cats);
+ if (rc != SEPOL_OK) {
+ cil_destroy_catset(catset);
+ goto exit;
+ }
+ cil_tree_node_init(&cat_node);
+ cat_node->flavor = CIL_CATSET;
+ cat_node->data = catset;
+ cil_list_append(((struct cil_symtab_datum*)catset)->nodes,
+ CIL_LIST_ITEM, cat_node);
+ new_arg->arg = (struct cil_symtab_datum*)catset;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+
+ break;
+ }
+ case CIL_LEVEL: {
+ if (pc->cl_head != NULL) {
+ struct cil_level *level = NULL;
+ struct cil_tree_node *lvl_node = NULL;
+ cil_level_init(&level);
+
+ rc = cil_fill_level(pc->cl_head, level);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc);
+ cil_destroy_level(level);
+ goto exit;
+ }
+ cil_tree_node_init(&lvl_node);
+ lvl_node->flavor = CIL_LEVEL;
+ lvl_node->data = level;
+ cil_list_append(((struct cil_symtab_datum*)level)->nodes,
+ CIL_LIST_ITEM, lvl_node);
+ new_arg->arg = (struct cil_symtab_datum*)level;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+
+ break;
+ }
+ case CIL_LEVELRANGE: {
+ if (pc->cl_head != NULL) {
+ struct cil_levelrange *range = NULL;
+ struct cil_tree_node *range_node = NULL;
+ cil_levelrange_init(&range);
+
+ rc = cil_fill_levelrange(pc->cl_head, range);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc);
+ cil_destroy_levelrange(range);
+ goto exit;
+ }
+ cil_tree_node_init(&range_node);
+ range_node->flavor = CIL_LEVELRANGE;
+ range_node->data = range;
+ cil_list_append(((struct cil_symtab_datum*)range)->nodes,
+ CIL_LIST_ITEM, range_node);
+ new_arg->arg = (struct cil_symtab_datum*)range;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+
+ break;
+ }
+ case CIL_IPADDR: {
+ if (pc->cl_head != NULL) {
+ struct cil_ipaddr *ipaddr = NULL;
+ struct cil_tree_node *addr_node = NULL;
+ cil_ipaddr_init(&ipaddr);
+
+ rc = cil_fill_ipaddr(pc->cl_head, ipaddr);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to create anonymous ip address, rc; %d\n", rc);
+ cil_destroy_ipaddr(ipaddr);
+ goto exit;
+ }
+ cil_tree_node_init(&addr_node);
+ addr_node->flavor = CIL_IPADDR;
+ addr_node->data = ipaddr;
+ cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes,
+ CIL_LIST_ITEM, addr_node);
+ new_arg->arg = (struct cil_symtab_datum*)ipaddr;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+
+ break;
+ }
+ case CIL_CLASS:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_MAP_CLASS:
+ new_arg->arg_str = pc->data;
+ break;
+ case CIL_CLASSPERMISSION: {
+ if (pc->cl_head != NULL) {
+ struct cil_classpermission *cp = NULL;
+ struct cil_tree_node *cp_node = NULL;
+
+ cil_classpermission_init(&cp);
+ rc = cil_fill_classperms_list(pc, &cp->classperms);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to create anonymous classpermission\n");
+ cil_destroy_classpermission(cp);
+ goto exit;
+ }
+ cil_tree_node_init(&cp_node);
+ cp_node->flavor = CIL_CLASSPERMISSION;
+ cp_node->data = cp;
+ cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node);
+ new_arg->arg = (struct cil_symtab_datum*)cp;
+ } else {
+ new_arg->arg_str = pc->data;
+ }
+ break;
+ }
+ default:
+ cil_log(CIL_ERR, "Unexpected flavor: %d\n",
+ (((struct cil_param*)item->data)->flavor));
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ new_arg->param_str = ((struct cil_param*)item->data)->str;
+ new_arg->flavor = flavor;
+
+ cil_list_append(new_call->args, CIL_ARGS, new_arg);
+
+ pc = pc->next;
+ }
+
+ if (pc != NULL) {
+ cil_tree_log(current, CIL_ERR, "Unexpected arguments");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else if (new_call->args_tree != NULL) {
+ cil_tree_log(current, CIL_ERR, "Unexpected arguments");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (new_call->copied == 0) {
+ new_call->copied = 1;
+
+ rc = cil_check_recursive_call(current, macro_node);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_copy_ast(db, macro_node, current);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_call2(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_call *new_call = current->data;
+ int rc = SEPOL_ERR;
+ enum cil_sym_index sym_index = CIL_SYM_UNKNOWN;
+ struct cil_list_item *item;
+
+ if (new_call->args == NULL) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ cil_list_for_each(item, new_call->args) {
+ struct cil_args *arg = item->data;
+ if (arg->arg == NULL && arg->arg_str == NULL) {
+ cil_log(CIL_ERR, "Arguments not created correctly\n");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ switch (arg->flavor) {
+ case CIL_NAME:
+ if (arg->arg != NULL) {
+ continue; /* No need to resolve */
+ } else {
+ sym_index = CIL_SYM_NAMES;
+ }
+ break;
+ case CIL_LEVEL:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue; // anonymous, no need to resolve
+ } else {
+ sym_index = CIL_SYM_LEVELS;
+ }
+ break;
+ case CIL_LEVELRANGE:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue; // anonymous, no need to resolve
+ } else {
+ sym_index = CIL_SYM_LEVELRANGES;
+ }
+ break;
+ case CIL_CATSET:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue; // anonymous, no need to resolve
+ } else {
+ sym_index = CIL_SYM_CATS;
+ }
+ break;
+ case CIL_IPADDR:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue; // anonymous, no need to resolve
+ } else {
+ sym_index = CIL_SYM_IPADDRS;
+ }
+ break;
+ case CIL_CLASSPERMISSION:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue;
+ } else {
+ sym_index = CIL_SYM_CLASSPERMSETS;
+ }
+ break;
+ case CIL_TYPE:
+ if (arg->arg_str == NULL && arg->arg != NULL) {
+ continue; // anonymous, no need to resolve
+ } else {
+ sym_index = CIL_SYM_TYPES;
+ }
+ break;
+ case CIL_ROLE:
+ sym_index = CIL_SYM_ROLES;
+ break;
+ case CIL_USER:
+ sym_index = CIL_SYM_USERS;
+ break;
+ case CIL_SENS:
+ sym_index = CIL_SYM_SENS;
+ break;
+ case CIL_CAT:
+ sym_index = CIL_SYM_CATS;
+ break;
+ case CIL_CLASS:
+ case CIL_MAP_CLASS:
+ sym_index = CIL_SYM_CLASSES;
+ break;
+ case CIL_BOOL:
+ sym_index = CIL_SYM_BOOLS;
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (sym_index != CIL_SYM_UNKNOWN) {
+ rc = cil_resolve_name(current, arg->arg_str, sym_index, extra_args, &(arg->arg));
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_name_call_args(struct cil_call *call, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+ struct cil_list_item *item;
+ enum cil_sym_index param_index = CIL_SYM_UNKNOWN;
+ int rc = SEPOL_ERR;
+
+ if (call == NULL || name == NULL) {
+ goto exit;
+ }
+
+ if (call->args == NULL) {
+ goto exit;
+ }
+
+ cil_list_for_each(item, call->args) {
+ struct cil_args * arg = item->data;
+ rc = cil_flavor_to_symtab_index(arg->flavor, ¶m_index);
+ if (param_index == sym_index) {
+ if (name == arg->param_str) {
+ *datum = arg->arg;
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_ERR;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struct cil_list **datum_expr, struct cil_tree_node *parent, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ struct cil_symtab_datum *res_datum = NULL;
+ enum cil_sym_index sym_index = CIL_SYM_UNKNOWN;
+
+ switch (str_expr->flavor) {
+ case CIL_BOOL:
+ sym_index = CIL_SYM_BOOLS;
+ break;
+ case CIL_TUNABLE:
+ sym_index = CIL_SYM_TUNABLES;
+ break;
+ case CIL_TYPE:
+ sym_index = CIL_SYM_TYPES;
+ break;
+ case CIL_ROLE:
+ sym_index = CIL_SYM_ROLES;
+ break;
+ case CIL_USER:
+ sym_index = CIL_SYM_USERS;
+ break;
+ case CIL_CAT:
+ sym_index = CIL_SYM_CATS;
+ break;
+ default:
+ break;
+ }
+
+ cil_list_init(datum_expr, str_expr->flavor);
+
+ cil_list_for_each(curr, str_expr) {
+ switch (curr->flavor) {
+ case CIL_STRING:
+ rc = cil_resolve_name(parent, curr->data, sym_index, extra_args, &res_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) {
+ cil_type_used(res_datum);
+ }
+
+ cil_list_append(*datum_expr, CIL_DATUM, res_datum);
+ break;
+ case CIL_LIST: {
+ struct cil_list *datum_sub_expr;
+ rc = cil_resolve_expr(expr_type, curr->data, &datum_sub_expr, parent, extra_args);
+ if (rc != SEPOL_OK) {
+ cil_list_destroy(&datum_sub_expr, CIL_TRUE);
+ goto exit;
+ }
+ cil_list_append(*datum_expr, CIL_LIST, datum_sub_expr);
+ break;
+ }
+ default:
+ cil_list_append(*datum_expr, curr->flavor, curr->data);
+ break;
+ }
+ }
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_booleanif *bif = (struct cil_booleanif*)current->data;
+
+ rc = cil_resolve_expr(CIL_BOOLEANIF, bif->str_expr, &bif->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_evaluate_tunable_expr(struct cil_list_item *curr);
+
+static int __cil_evaluate_tunable_expr_helper(struct cil_list_item *curr)
+{
+ if (curr == NULL) {
+ return CIL_FALSE;
+ } else if (curr->flavor == CIL_DATUM) {
+ struct cil_tunable *tun = curr->data;
+ return tun->value;
+ } else if (curr->flavor == CIL_LIST) {
+ struct cil_list *l = curr->data;
+ return __cil_evaluate_tunable_expr(l->head);
+ } else {
+ return CIL_FALSE;
+ }
+}
+
+static int __cil_evaluate_tunable_expr(struct cil_list_item *curr)
+{
+ /* Assumes expression is well-formed */
+
+ if (curr == NULL) {
+ return CIL_FALSE;
+ } else if (curr->flavor == CIL_OP) {
+ uint16_t v1, v2;
+ enum cil_flavor op_flavor = (enum cil_flavor)curr->data;
+
+ v1 = __cil_evaluate_tunable_expr_helper(curr->next);
+
+ if (op_flavor == CIL_NOT) return !v1;
+
+ v2 = __cil_evaluate_tunable_expr_helper(curr->next->next);
+
+ if (op_flavor == CIL_AND) return (v1 && v2);
+ else if (op_flavor == CIL_OR) return (v1 || v2);
+ else if (op_flavor == CIL_XOR) return (v1 ^ v2);
+ else if (op_flavor == CIL_EQ) return (v1 == v2);
+ else if (op_flavor == CIL_NEQ) return (v1 != v2);
+ else return CIL_FALSE;
+ } else {
+ uint16_t v;
+ for (;curr; curr = curr->next) {
+ v = __cil_evaluate_tunable_expr_helper(curr);
+ if (v) return v;
+ }
+ return CIL_FALSE;
+ }
+}
+
+int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args)
+{
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = NULL;
+ int rc = SEPOL_ERR;
+ struct cil_tunableif *tif = (struct cil_tunableif*)current->data;
+ uint16_t result = CIL_FALSE;
+ struct cil_tree_node *true_node = NULL;
+ struct cil_tree_node *false_node = NULL;
+ struct cil_condblock *cb = NULL;
+
+ if (args != NULL) {
+ db = args->db;
+ }
+
+ rc = cil_resolve_expr(CIL_TUNABLEIF, tif->str_expr, &tif->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ result = __cil_evaluate_tunable_expr(tif->datum_expr->head);
+
+ if (current->cl_head != NULL && current->cl_head->flavor == CIL_CONDBLOCK) {
+ cb = current->cl_head->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ true_node = current->cl_head;
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ false_node = current->cl_head;
+ }
+ }
+
+ if (current->cl_head != NULL && current->cl_head->next != NULL && current->cl_head->next->flavor == CIL_CONDBLOCK) {
+ cb = current->cl_head->next->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ true_node = current->cl_head->next;
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ false_node = current->cl_head->next;
+ }
+ }
+
+ if (result == CIL_TRUE) {
+ if (true_node != NULL) {
+ rc = cil_copy_ast(db, true_node, current->parent);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else {
+ if (false_node != NULL) {
+ rc = cil_copy_ast(db, false_node, current->parent);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ cil_tree_children_destroy(current);
+ current->cl_head = NULL;
+ current->cl_tail = NULL;
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_userattributeset *attrusers = current->data;
+ struct cil_symtab_datum *attr_datum = NULL;
+ struct cil_tree_node *attr_node = NULL;
+ struct cil_userattribute *attr = NULL;
+
+ rc = cil_resolve_name(current, attrusers->attr_str, CIL_SYM_USERS, extra_args, &attr_datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ attr_node = attr_datum->nodes->head->data;
+
+ if (attr_node->flavor != CIL_USERATTRIBUTE) {
+ rc = SEPOL_ERR;
+ cil_log(CIL_ERR, "Attribute user not an attribute\n");
+ goto exit;
+ }
+ attr = (struct cil_userattribute*)attr_datum;
+
+ rc = cil_resolve_expr(CIL_USERATTRIBUTESET, attrusers->str_expr, &attrusers->datum_expr, current, extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = cil_verify_no_self_reference(attr_datum, attrusers->datum_expr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ if (attr->expr_list == NULL) {
+ cil_list_init(&attr->expr_list, CIL_USERATTRIBUTE);
+ }
+
+ cil_list_append(attr->expr_list, CIL_LIST, attrusers->datum_expr);
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
+{
+ int rc = SEPOL_OK;
+ struct cil_args_resolve *args = extra_args;
+ enum cil_pass pass = 0;
+ struct cil_list *ins = args->in_list;
+
+ if (node == NULL || args == NULL) {
+ goto exit;
+ }
+
+ pass = args->pass;
+ switch (pass) {
+ case CIL_PASS_TIF:
+ if (node->flavor == CIL_TUNABLEIF) {
+ rc = cil_resolve_tunif(node, args);
+ }
+ break;
+ case CIL_PASS_IN:
+ if (node->flavor == CIL_IN) {
+ // due to ordering issues, in statements are just gathered here and
+ // resolved together in cil_resolve_in_list once all are found
+ cil_list_prepend(ins, CIL_NODE, node);
+ }
+ break;
+ case CIL_PASS_BLKIN_LINK:
+ if (node->flavor == CIL_BLOCKINHERIT) {
+ rc = cil_resolve_blockinherit_link(node, args);
+ }
+ break;
+ case CIL_PASS_BLKIN_COPY:
+ if (node->flavor == CIL_BLOCK) {
+ rc = cil_resolve_blockinherit_copy(node, args);
+ }
+ break;
+ case CIL_PASS_BLKABS:
+ if (node->flavor == CIL_BLOCKABSTRACT) {
+ rc = cil_resolve_blockabstract(node, args);
+ }
+ break;
+ case CIL_PASS_MACRO:
+ if (node->flavor == CIL_CALL && args->macro != NULL) {
+ rc = cil_resolve_call1(node, args);
+ }
+ break;
+ case CIL_PASS_CALL1:
+ if (node->flavor == CIL_CALL) {
+ rc = cil_resolve_call1(node, args);
+ }
+ break;
+ case CIL_PASS_CALL2:
+ if (node->flavor == CIL_CALL) {
+ rc = cil_resolve_call2(node, args);
+ }
+ break;
+ case CIL_PASS_ALIAS1:
+ switch (node->flavor) {
+ case CIL_TYPEALIASACTUAL:
+ rc = cil_resolve_aliasactual(node, args, CIL_TYPE);
+ break;
+ case CIL_SENSALIASACTUAL:
+ rc = cil_resolve_aliasactual(node, args, CIL_SENS);
+ break;
+ case CIL_CATALIASACTUAL:
+ rc = cil_resolve_aliasactual(node, args, CIL_CAT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case CIL_PASS_ALIAS2:
+ switch (node->flavor) {
+ case CIL_TYPEALIAS:
+ rc = cil_resolve_alias_to_actual(node, CIL_TYPE);
+ break;
+ case CIL_SENSALIAS:
+ rc = cil_resolve_alias_to_actual(node, CIL_SENS);
+ break;
+ case CIL_CATALIAS:
+ rc = cil_resolve_alias_to_actual(node, CIL_CAT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case CIL_PASS_MISC1:
+ switch (node->flavor) {
+ case CIL_SIDORDER:
+ rc = cil_resolve_sidorder(node, args);
+ break;
+ case CIL_CLASSORDER:
+ rc = cil_resolve_classorder(node, args);
+ break;
+ case CIL_CATORDER:
+ rc = cil_resolve_catorder(node, args);
+ break;
+ case CIL_SENSITIVITYORDER:
+ rc = cil_resolve_sensitivityorder(node, args);
+ break;
+ case CIL_BOOLEANIF:
+ rc = cil_resolve_boolif(node, args);
+ break;
+ default:
+ break;
+ }
+ break;
+ case CIL_PASS_MLS:
+ switch (node->flavor) {
+ case CIL_CATSET:
+ rc = cil_resolve_catset(node, (struct cil_catset*)node->data, args);
+ break;
+ default:
+ break;
+ }
+ break;
+ case CIL_PASS_MISC2:
+ switch (node->flavor) {
+ case CIL_SENSCAT:
+ rc = cil_resolve_senscat(node, args);
+ break;
+ case CIL_CLASSCOMMON:
+ rc = cil_resolve_classcommon(node, args);
+ break;
+ default:
+ break;
+ }
+ break;
+ case CIL_PASS_MISC3:
+ switch (node->flavor) {
+ case CIL_TYPEATTRIBUTESET:
+ rc = cil_resolve_typeattributeset(node, args);
+ break;
+ case CIL_TYPEBOUNDS:
+ rc = cil_resolve_bounds(node, args, CIL_TYPE);
+ break;
+ case CIL_TYPEPERMISSIVE:
+ rc = cil_resolve_typepermissive(node, args);
+ break;
+ case CIL_NAMETYPETRANSITION:
+ rc = cil_resolve_nametypetransition(node, args);
+ break;
+ case CIL_RANGETRANSITION:
+ rc = cil_resolve_rangetransition(node, args);
+ break;
+ case CIL_CLASSPERMISSIONSET:
+ rc = cil_resolve_classpermissionset(node, (struct cil_classpermissionset*)node->data, args);
+ break;
+ case CIL_CLASSMAPPING:
+ rc = cil_resolve_classmapping(node, args);
+ break;
+ case CIL_AVRULE:
+ case CIL_AVRULEX:
+ rc = cil_resolve_avrule(node, args);
+ break;
+ case CIL_PERMISSIONX:
+ rc = cil_resolve_permissionx(node, (struct cil_permissionx*)node->data, args);
+ break;
+ case CIL_TYPE_RULE:
+ rc = cil_resolve_type_rule(node, args);
+ break;
+ case CIL_USERROLE:
+ rc = cil_resolve_userrole(node, args);
+ break;
+ case CIL_USERLEVEL:
+ rc = cil_resolve_userlevel(node, args);
+ break;
+ case CIL_USERRANGE:
+ rc = cil_resolve_userrange(node, args);
+ break;
+ case CIL_USERBOUNDS:
+ rc = cil_resolve_bounds(node, args, CIL_USER);
+ break;
+ case CIL_USERPREFIX:
+ rc = cil_resolve_userprefix(node, args);
+ break;
+ case CIL_SELINUXUSER:
+ case CIL_SELINUXUSERDEFAULT:
+ rc = cil_resolve_selinuxuser(node, args);
+ break;
+ case CIL_ROLEATTRIBUTESET:
+ rc = cil_resolve_roleattributeset(node, args);
+ break;
+ case CIL_ROLETYPE:
+ rc = cil_resolve_roletype(node, args);
+ break;
+ case CIL_ROLETRANSITION:
+ rc = cil_resolve_roletransition(node, args);
+ break;
+ case CIL_ROLEALLOW:
+ rc = cil_resolve_roleallow(node, args);
+ break;
+ case CIL_ROLEBOUNDS:
+ rc = cil_resolve_bounds(node, args, CIL_ROLE);
+ break;
+ case CIL_LEVEL:
+ rc = cil_resolve_level(node, (struct cil_level*)node->data, args);
+ break;
+ case CIL_LEVELRANGE:
+ rc = cil_resolve_levelrange(node, (struct cil_levelrange*)node->data, args);
+ break;
+ case CIL_CONSTRAIN:
+ rc = cil_resolve_constrain(node, args);
+ break;
+ case CIL_MLSCONSTRAIN:
+ rc = cil_resolve_constrain(node, args);
+ break;
+ case CIL_VALIDATETRANS:
+ case CIL_MLSVALIDATETRANS:
+ rc = cil_resolve_validatetrans(node, args);
+ break;
+ case CIL_CONTEXT:
+ rc = cil_resolve_context(node, (struct cil_context*)node->data, args);
+ break;
+ case CIL_FILECON:
+ rc = cil_resolve_filecon(node, args);
+ break;
+ case CIL_PORTCON:
+ rc = cil_resolve_portcon(node, args);
+ break;
+ case CIL_NODECON:
+ rc = cil_resolve_nodecon(node, args);
+ break;
+ case CIL_GENFSCON:
+ rc = cil_resolve_genfscon(node, args);
+ break;
+ case CIL_NETIFCON:
+ rc = cil_resolve_netifcon(node, args);
+ break;
+ case CIL_PIRQCON:
+ rc = cil_resolve_pirqcon(node, args);
+ break;
+ case CIL_IOMEMCON:
+ rc = cil_resolve_iomemcon(node, args);
+ break;
+ case CIL_IOPORTCON:
+ rc = cil_resolve_ioportcon(node, args);
+ break;
+ case CIL_PCIDEVICECON:
+ rc = cil_resolve_pcidevicecon(node, args);
+ break;
+ case CIL_DEVICETREECON:
+ rc = cil_resolve_devicetreecon(node, args);
+ break;
+ case CIL_FSUSE:
+ rc = cil_resolve_fsuse(node, args);
+ break;
+ case CIL_SIDCONTEXT:
+ rc = cil_resolve_sidcontext(node, args);
+ break;
+ case CIL_DEFAULTUSER:
+ case CIL_DEFAULTROLE:
+ case CIL_DEFAULTTYPE:
+ rc = cil_resolve_default(node, args);
+ break;
+ case CIL_DEFAULTRANGE:
+ rc = cil_resolve_defaultrange(node, args);
+ break;
+ case CIL_USERATTRIBUTESET:
+ rc = cil_resolve_userattributeset(node, args);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+
+exit:
+ return rc;
+}
+
+int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve *args = extra_args;
+ enum cil_pass pass = args->pass;
+ struct cil_tree_node *optstack = args->optstack;
+ struct cil_tree_node *boolif = args->boolif;
+ struct cil_tree_node *blockstack = args->blockstack;
+ struct cil_tree_node *macro = args->macro;
+
+ if (node == NULL) {
+ goto exit;
+ }
+
+ if (optstack != NULL) {
+ if (node->flavor == CIL_TUNABLE || node->flavor == CIL_MACRO) {
+ /* tuanbles and macros are not allowed in optionals*/
+ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node));
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ if (blockstack != NULL) {
+ if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) {
+ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node));
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ if (macro != NULL) {
+ if (node->flavor == CIL_BLOCKINHERIT ||
+ node->flavor == CIL_BLOCK ||
+ node->flavor == CIL_BLOCKABSTRACT ||
+ node->flavor == CIL_MACRO) {
+ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node));
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ if (boolif != NULL) {
+ if (!(node->flavor == CIL_CONDBLOCK ||
+ node->flavor == CIL_AVRULE ||
+ node->flavor == CIL_TYPE_RULE ||
+ node->flavor == CIL_CALL ||
+ node->flavor == CIL_TUNABLEIF ||
+ node->flavor == CIL_NAMETYPETRANSITION)) {
+ if (((struct cil_booleanif*)boolif->data)->preserved_tunable) {
+ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node));
+ } else {
+ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node));
+ }
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ if (node->flavor == CIL_MACRO) {
+ if (pass != CIL_PASS_TIF && pass != CIL_PASS_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ }
+ }
+
+ if (node->flavor == CIL_BLOCK && ((((struct cil_block*)node->data)->is_abstract == CIL_TRUE) && (pass > CIL_PASS_BLKABS))) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ rc = __cil_resolve_ast_node(node, extra_args);
+ if (rc == SEPOL_ENOENT) {
+ enum cil_log_level lvl = CIL_ERR;
+
+ if (optstack != NULL) {
+ lvl = CIL_WARN;
+
+ struct cil_optional *opt = (struct cil_optional *)optstack->data;
+ struct cil_tree_node *opt_node = opt->datum.nodes->head->data;
+ cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name);
+ /* disable an optional if something failed to resolve */
+ opt->enabled = CIL_FALSE;
+ rc = SEPOL_OK;
+ }
+
+ cil_tree_log(node, lvl, "Failed to resolve '%s' in %s statement", args->last_resolved_name, cil_node_to_string(node));
+ goto exit;
+ }
+
+ return rc;
+
+exit:
+ return rc;
+}
+
+int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_tree_node *optstack = NULL;
+ struct cil_tree_node *parent = NULL;
+ struct cil_tree_node *blockstack = NULL;
+ struct cil_tree_node *new = NULL;
+
+ if (current == NULL || extra_args == NULL) {
+ goto exit;
+ }
+
+ optstack = args->optstack;
+ parent = current->parent;
+ blockstack = args->blockstack;
+
+ if (parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
+ /* push this node onto a stack */
+ cil_tree_node_init(&new);
+
+ new->data = parent->data;
+ new->flavor = parent->flavor;
+
+ if (parent->flavor == CIL_OPTIONAL) {
+ if (optstack != NULL) {
+ optstack->parent = new;
+ new->cl_head = optstack;
+ }
+ args->optstack = new;
+ } else if (parent->flavor == CIL_BLOCK) {
+ if (blockstack != NULL) {
+ blockstack->parent = new;
+ new->cl_head = blockstack;
+ }
+ args->blockstack = new;
+ }
+ } else if (parent->flavor == CIL_BOOLEANIF) {
+ args->boolif = parent;
+ } else if (parent->flavor == CIL_MACRO) {
+ args->macro = parent;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+
+}
+
+int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_tree_node *parent = NULL;
+ struct cil_tree_node *blockstack = NULL;
+
+ if (current == NULL || extra_args == NULL) {
+ goto exit;
+ }
+
+ parent = current->parent;
+
+ if (parent->flavor == CIL_MACRO) {
+ args->macro = NULL;
+ } else if (parent->flavor == CIL_OPTIONAL) {
+ struct cil_tree_node *optstack;
+
+ if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) {
+ *(args->changed) = CIL_TRUE;
+ cil_tree_children_destroy(parent);
+ }
+
+ /* pop off the stack */
+ optstack = args->optstack;
+ args->optstack = optstack->cl_head;
+ if (optstack->cl_head) {
+ optstack->cl_head->parent = NULL;
+ }
+ free(optstack);
+ } else if (parent->flavor == CIL_BOOLEANIF) {
+ args->boolif = NULL;
+ } else if (parent->flavor == CIL_BLOCK) {
+ /* pop off the stack */
+ blockstack = args->blockstack;
+ args->blockstack = blockstack->cl_head;
+ if (blockstack->cl_head) {
+ blockstack->cl_head->parent = NULL;
+ }
+ free(blockstack);
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve extra_args;
+ enum cil_pass pass = CIL_PASS_TIF;
+ uint32_t changed = 0;
+
+ if (db == NULL || current == NULL) {
+ goto exit;
+ }
+
+ extra_args.db = db;
+ extra_args.pass = pass;
+ extra_args.changed = &changed;
+ extra_args.last_resolved_name = NULL;
+ extra_args.optstack = NULL;
+ extra_args.boolif= NULL;
+ extra_args.macro = NULL;
+ extra_args.sidorder_lists = NULL;
+ extra_args.classorder_lists = NULL;
+ extra_args.unordered_classorder_lists = NULL;
+ extra_args.catorder_lists = NULL;
+ extra_args.sensitivityorder_lists = NULL;
+ extra_args.in_list = NULL;
+ extra_args.blockstack = NULL;
+
+ cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
+ cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM);
+ cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM);
+ cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM);
+ cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
+ cil_list_init(&extra_args.in_list, CIL_IN);
+ for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
+ extra_args.pass = pass;
+ rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_INFO, "Pass %i of resolution failed\n", pass);
+ goto exit;
+ }
+
+ if (pass == CIL_PASS_IN) {
+ rc = cil_resolve_in_list(&extra_args);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cil_list_destroy(&extra_args.in_list, CIL_FALSE);
+ }
+
+ if (pass == CIL_PASS_MISC1) {
+ db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL);
+ if (db->sidorder == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ db->classorder = __cil_ordered_lists_merge_all(&extra_args.classorder_lists, &extra_args.unordered_classorder_lists);
+ if (db->classorder == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ db->catorder = __cil_ordered_lists_merge_all(&extra_args.catorder_lists, NULL);
+ if (db->catorder == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ cil_set_cat_values(db->catorder, db);
+ db->sensitivityorder = __cil_ordered_lists_merge_all(&extra_args.sensitivityorder_lists, NULL);
+ if (db->sensitivityorder == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = __cil_verify_ordered(current, CIL_SID);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_verify_ordered(current, CIL_CLASS);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_verify_ordered(current, CIL_CAT);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_verify_ordered(current, CIL_SENS);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ if (changed && (pass > CIL_PASS_CALL1)) {
+ /* Need to re-resolve because an optional was disabled that contained
+ * one or more declarations. We only need to reset to the call1 pass
+ * because things done in the preceeding passes aren't allowed in
+ * optionals, and thus can't be disabled.
+ * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment
+ * it to CIL_PASS_CALL2
+ */
+ cil_log(CIL_INFO, "Resetting declarations\n");
+
+ if (pass >= CIL_PASS_MISC1) {
+ __cil_ordered_lists_reset(&extra_args.sidorder_lists);
+ __cil_ordered_lists_reset(&extra_args.classorder_lists);
+ __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists);
+ __cil_ordered_lists_reset(&extra_args.catorder_lists);
+ __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists);
+ cil_list_destroy(&db->sidorder, CIL_FALSE);
+ cil_list_destroy(&db->classorder, CIL_FALSE);
+ cil_list_destroy(&db->catorder, CIL_FALSE);
+ cil_list_destroy(&db->sensitivityorder, CIL_FALSE);
+ }
+
+ pass = CIL_PASS_CALL1;
+
+ rc = cil_reset_ast(current);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Failed to reset declarations\n");
+ goto exit;
+ }
+ }
+
+ /* reset the arguments */
+ changed = 0;
+ while (extra_args.optstack != NULL) {
+ struct cil_tree_node *curr = extra_args.optstack;
+ struct cil_tree_node *next = curr->cl_head;
+ free(curr);
+ extra_args.optstack = next;
+ }
+ while (extra_args.blockstack!= NULL) {
+ struct cil_tree_node *curr = extra_args.blockstack;
+ struct cil_tree_node *next = curr->cl_head;
+ free(curr);
+ extra_args.blockstack= next;
+ }
+ }
+
+ rc = __cil_verify_initsids(db->sidorder);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = SEPOL_OK;
+exit:
+ __cil_ordered_lists_destroy(&extra_args.sidorder_lists);
+ __cil_ordered_lists_destroy(&extra_args.classorder_lists);
+ __cil_ordered_lists_destroy(&extra_args.catorder_lists);
+ __cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
+ cil_list_destroy(&extra_args.in_list, CIL_FALSE);
+
+ return rc;
+}
+
+static int __cil_resolve_name_with_root(struct cil_db *db, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+ symtab_t *symtab = &((struct cil_root *)db->ast->root->data)->symtab[sym_index];
+
+ return cil_symtab_get_datum(symtab, name, datum);
+}
+
+static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+ int rc = SEPOL_ERR;
+ symtab_t *symtab = NULL;
+
+ while (node != NULL && rc != SEPOL_OK) {
+ switch (node->flavor) {
+ case CIL_ROOT:
+ goto exit;
+ break;
+ case CIL_BLOCK:
+ symtab = &((struct cil_block*)node->data)->symtab[sym_index];
+ rc = cil_symtab_get_datum(symtab, name, datum);
+ break;
+ case CIL_BLOCKINHERIT: {
+ struct cil_blockinherit *inherit = node->data;
+ rc = __cil_resolve_name_with_parents(node->parent, name, sym_index, datum);
+ if (rc != SEPOL_OK) {
+ /* Continue search in original block's parent */
+ rc = __cil_resolve_name_with_parents(NODE(inherit->block), name, sym_index, datum);
+ goto exit;
+ }
+ }
+ break;
+ case CIL_MACRO: {
+ struct cil_macro *macro = node->data;
+ symtab = ¯o->symtab[sym_index];
+ rc = cil_symtab_get_datum(symtab, name, datum);
+ }
+ break;
+ case CIL_CALL: {
+ struct cil_call *call = node->data;
+ rc = cil_resolve_name_call_args(call, name, sym_index, datum);
+ if (rc != SEPOL_OK) {
+ /* Continue search in macro's parent */
+ rc = __cil_resolve_name_with_parents(NODE(call->macro)->parent, name, sym_index, datum);
+ }
+ }
+ break;
+ case CIL_IN:
+ /* In block symtabs only exist before resolving the AST */
+ case CIL_CONDBLOCK:
+ /* Cond block symtabs only exist before resolving the AST */
+ default:
+ break;
+ }
+
+ node = node->parent;
+ }
+
+exit:
+ return rc;
+}
+
+static int __cil_resolve_name_helper(struct cil_db *db, struct cil_tree_node *node, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
+{
+ int rc = SEPOL_ERR;
+
+ rc = __cil_resolve_name_with_parents(node, name, sym_index, datum);
+ if (rc != SEPOL_OK) {
+ rc = __cil_resolve_name_with_root(db, name, sym_index, datum);
+ }
+ return rc;
+}
+
+int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum)
+{
+ int rc = SEPOL_ERR;
+ struct cil_args_resolve *args = extra_args;
+ struct cil_db *db = args->db;
+ struct cil_tree_node *node = NULL;
+
+ if (name == NULL) {
+ cil_log(CIL_ERR, "Invalid call to cil_resolve_name\n");
+ goto exit;
+ }
+
+ *datum = NULL;
+
+ if (strchr(name,'.') == NULL) {
+ /* No '.' in name */
+ rc = __cil_resolve_name_helper(db, ast_node->parent, name, sym_index, datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else {
+ char *sp = NULL;
+ char *name_dup = cil_strdup(name);
+ char *current = strtok_r(name_dup, ".", &sp);
+ char *next = strtok_r(NULL, ".", &sp);
+ symtab_t *symtab = NULL;
+
+ node = ast_node;
+ if (*name == '.') {
+ /* Leading '.' */
+ symtab = &((struct cil_root *)db->ast->root->data)->symtab[CIL_SYM_BLOCKS];
+ } else {
+ rc = __cil_resolve_name_helper(db, node->parent, current, CIL_SYM_BLOCKS, datum);
+ if (rc != SEPOL_OK) {
+ free(name_dup);
+ goto exit;
+ }
+ symtab = (*datum)->symtab;
+ }
+ /* Keep looking up blocks by name until only last part of name remains */
+ while (next != NULL) {
+ rc = cil_symtab_get_datum(symtab, current, datum);
+ if (rc != SEPOL_OK) {
+ free(name_dup);
+ goto exit;
+ }
+ node = NODE(*datum);
+ if (node->flavor == CIL_BLOCK) {
+ symtab = &((struct cil_block*)node->data)->symtab[CIL_SYM_BLOCKS];
+ } else {
+ if (ast_node->flavor != CIL_IN) {
+ cil_log(CIL_WARN, "Can only use %s name for name resolution in \"in\" blocks\n", cil_node_to_string(node));
+ free(name_dup);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ if (node->flavor == CIL_MACRO) {
+ struct cil_macro *macro = node->data;
+ symtab = ¯o->symtab[sym_index];
+ } else {
+ /* optional */
+ symtab = (*datum)->symtab;
+ }
+ }
+ current = next;
+ next = strtok_r(NULL, ".", &sp);
+ }
+ symtab = &(symtab[sym_index]);
+ rc = cil_symtab_get_datum(symtab, current, datum);
+ free(name_dup);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ if (rc != SEPOL_OK) {
+ *datum = NULL;
+ }
+
+ if (*datum != NULL) {
+ /* If this datum is an alias, then return the actual node
+ * This depends on aliases already being processed
+ */
+ node = NODE(*datum);
+ if (node->flavor == CIL_TYPEALIAS || node->flavor == CIL_SENSALIAS
+ || node->flavor == CIL_CATALIAS) {
+ struct cil_alias *alias = (struct cil_alias *)(*datum);
+ if (alias->actual) {
+ *datum = alias->actual;
+ }
+ }
+ }
+
+ args->last_resolved_name = name;
+
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
new file mode 100644
index 0000000..1175f97
--- /dev/null
+++ b/libsepol/cil/src/cil_resolve_ast.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_RESOLVE_AST_H_
+#define CIL_RESOLVE_AST_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+
+int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classperms(struct cil_tree_node *current, struct cil_classperms *cp, void *extra_args);
+int cil_resolve_classpermissionset(struct cil_tree_node *current, struct cil_classpermissionset *cps, void *extra_args);
+int cil_resolve_classperms_list(struct cil_tree_node *current, struct cil_list *cp_list, void *extra_args);
+int cil_resolve_avrule(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typealias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typebounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_typepermissive(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_rangetransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_classmapping(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userrole(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userbounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roletype(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roleallow(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_rolebounds(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sensalias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_catalias(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sensitivityorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_cat_list(struct cil_tree_node *current, struct cil_list *cat_list, struct cil_list *res_cat_list, void *extra_args);
+int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args);
+int cil_resolve_senscat(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_level(struct cil_tree_node *current, struct cil_level *level, void *extra_args);
+int cil_resolve_levelrange(struct cil_tree_node *current, struct cil_levelrange *levelrange, void *extra_args);
+int cil_resolve_constrain(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args);
+int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_netifcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_iomemcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_ioportcon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_pcidevicecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_fsuse(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sidcontext(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_blockinherit(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_in(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_call1(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_call2(struct cil_tree_node *, void *extra_args);
+int cil_resolve_name_call_args(struct cil_call *call, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum);
+int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struct cil_list **datum_expr, struct cil_tree_node *parent, void *extra_args);
+int cil_resolve_boolif(struct cil_tree_node *current, void *extra_args);
+int cil_evaluate_expr(struct cil_list *datum_expr, uint16_t *result);
+int cil_resolve_tunif(struct cil_tree_node *current, void *extra_args);
+
+int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current);
+int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, void *extra_args, struct cil_symtab_datum **datum);
+
+#endif /* CIL_RESOLVE_AST_H_ */
diff --git a/libsepol/cil/src/cil_stack.c b/libsepol/cil/src/cil_stack.c
new file mode 100644
index 0000000..bbfb961
--- /dev/null
+++ b/libsepol/cil/src/cil_stack.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+
+#include "cil_internal.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_stack.h"
+
+
+#define CIL_STACK_INIT_SIZE 16
+
+void cil_stack_init(struct cil_stack **stack)
+{
+ struct cil_stack *new_stack = cil_malloc(sizeof(*new_stack));
+ new_stack->stack = cil_malloc(sizeof(*(new_stack->stack)) * CIL_STACK_INIT_SIZE);
+ new_stack->size = CIL_STACK_INIT_SIZE;
+ new_stack->pos = -1;
+ *stack = new_stack;
+}
+
+void cil_stack_destroy(struct cil_stack **stack)
+{
+ if (stack == NULL || *stack == NULL) {
+ return;
+ }
+
+ free((*stack)->stack);
+ free(*stack);
+ *stack = NULL;
+}
+
+void cil_stack_empty(struct cil_stack *stack)
+{
+ stack->pos = -1;
+}
+
+int cil_stack_is_empty(struct cil_stack *stack)
+{
+ return (stack->pos == -1);
+}
+
+void cil_stack_push(struct cil_stack *stack, enum cil_flavor flavor, void *data)
+{
+ stack->pos++;
+
+ if (stack->pos == stack->size) {
+ stack->size *= 2;
+ stack->stack = cil_realloc(stack->stack, sizeof(*stack->stack) * stack->size);
+ }
+
+ stack->stack[stack->pos].flavor = flavor;
+ stack->stack[stack->pos].data = data;
+}
+
+struct cil_stack_item *cil_stack_pop(struct cil_stack *stack)
+{
+ if (stack->pos == -1) {
+ return NULL;
+ }
+
+ stack->pos--;
+ return &stack->stack[stack->pos + 1];
+}
+
+struct cil_stack_item *cil_stack_peek(struct cil_stack *stack)
+{
+ if (stack->pos < 0) {
+ return NULL;
+ }
+
+ return &stack->stack[stack->pos];
+}
+
+struct cil_stack_item *cil_stack_peek_at(struct cil_stack *stack, int pos)
+{
+ int peekpos = stack->pos - pos;
+
+ if (peekpos < 0 || peekpos > stack->pos) {
+ return NULL;
+ }
+
+ return &stack->stack[peekpos];
+}
diff --git a/libsepol/cil/src/cil_stack.h b/libsepol/cil/src/cil_stack.h
new file mode 100644
index 0000000..b78535a
--- /dev/null
+++ b/libsepol/cil/src/cil_stack.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_STACK_H_
+#define CIL_STACK_H_
+
+struct cil_stack {
+ struct cil_stack_item *stack;
+ int size;
+ int pos;
+};
+
+struct cil_stack_item {
+ enum cil_flavor flavor;
+ void *data;
+};
+
+#define cil_stack_for_each_starting_at(stack, start, pos, item) \
+ for (pos = start, item = cil_stack_peek_at(stack, pos); item != NULL; pos++, item = cil_stack_peek_at(stack, pos))
+
+#define cil_stack_for_each(stack, pos, item) cil_stack_for_each_starting_at(stack, 0, pos, item)
+
+
+void cil_stack_init(struct cil_stack **stack);
+void cil_stack_destroy(struct cil_stack **stack);
+
+void cil_stack_empty(struct cil_stack *stack);
+int cil_stack_is_empty(struct cil_stack *stack);
+
+void cil_stack_push(struct cil_stack *stack, enum cil_flavor flavor, void *data);
+struct cil_stack_item *cil_stack_pop(struct cil_stack *stack);
+struct cil_stack_item *cil_stack_peek(struct cil_stack *stack);
+struct cil_stack_item *cil_stack_peek_at(struct cil_stack *stack, int pos);
+
+
+#endif
diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c
new file mode 100644
index 0000000..ad2a334
--- /dev/null
+++ b/libsepol/cil/src/cil_strpool.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2014 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "cil_mem.h"
+#include "cil_strpool.h"
+
+#include "cil_log.h"
+#define CIL_STRPOOL_TABLE_SIZE 1 << 15
+
+struct cil_strpool_entry {
+ char *str;
+};
+
+static hashtab_t cil_strpool_tab = NULL;
+
+static unsigned int cil_strpool_hash(hashtab_t h, hashtab_key_t key)
+{
+ char *p, *keyp;
+ size_t size;
+ unsigned int val;
+
+ val = 0;
+ keyp = (char*)key;
+ size = strlen(keyp);
+ for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+ val =
+ (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+ return val & (h->size - 1);
+}
+
+static int cil_strpool_compare(hashtab_t h __attribute__ ((unused)), hashtab_key_t key1, hashtab_key_t key2)
+{
+ char *keyp1 = (char*)key1;
+ char *keyp2 = (char*)key2;
+ return strcmp(keyp1, keyp2);
+}
+
+char *cil_strpool_add(const char *str)
+{
+ struct cil_strpool_entry *strpool_ref = NULL;
+
+ strpool_ref = hashtab_search(cil_strpool_tab, (hashtab_key_t)str);
+ if (strpool_ref == NULL) {
+ strpool_ref = cil_malloc(sizeof(*strpool_ref));
+ strpool_ref->str = cil_strdup(str);
+ int rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref);
+ if (rc != SEPOL_OK) {
+ (*cil_mem_error_handler)();
+ }
+ }
+
+ return strpool_ref->str;
+}
+
+static int cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
+{
+ struct cil_strpool_entry *strpool_ref = (struct cil_strpool_entry*)d;
+ free(strpool_ref->str);
+ free(strpool_ref);
+ return SEPOL_OK;
+}
+
+void cil_strpool_init(void)
+{
+ cil_strpool_tab = hashtab_create(cil_strpool_hash, cil_strpool_compare, CIL_STRPOOL_TABLE_SIZE);
+ if (cil_strpool_tab == NULL) {
+ (*cil_mem_error_handler)();
+ }
+}
+
+void cil_strpool_destroy(void)
+{
+ hashtab_map(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
+ hashtab_destroy(cil_strpool_tab);
+}
diff --git a/libsepol/cil/src/cil_strpool.h b/libsepol/cil/src/cil_strpool.h
new file mode 100644
index 0000000..a61a2d9
--- /dev/null
+++ b/libsepol/cil/src/cil_strpool.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_STRPOOL_H_
+#define CIL_STRPOOL_H_
+
+#include <sepol/policydb/hashtab.h>
+
+char *cil_strpool_add(const char *str);
+void cil_strpool_init(void);
+void cil_strpool_destroy(void);
+#endif /* CIL_STRPOOL_H_ */
diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c
new file mode 100644
index 0000000..3769979
--- /dev/null
+++ b/libsepol/cil/src/cil_symtab.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sepol/errcodes.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/symtab.h>
+
+#include "cil_internal.h"
+#include "cil_tree.h"
+#include "cil_symtab.h"
+#include "cil_mem.h"
+#include "cil_strpool.h"
+#include "cil_log.h"
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_symtab_error(const char* msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ cil_vlog(CIL_ERR, msg, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void cil_symtab_init(symtab_t *symtab, unsigned int size)
+{
+ int rc = symtab_init(symtab, size);
+ if (rc != SEPOL_OK) {
+ cil_symtab_error("Failed to create symtab\n");
+ }
+}
+
+void cil_symtab_datum_init(struct cil_symtab_datum *datum)
+{
+ datum->name = NULL;
+ datum->fqn = NULL;
+ datum->symtab = NULL;
+ cil_list_init(&datum->nodes, CIL_LIST_ITEM);
+}
+
+void cil_symtab_datum_destroy(struct cil_symtab_datum *datum)
+{
+ cil_list_destroy(&datum->nodes, 0);
+ cil_symtab_remove_datum(datum);
+}
+
+void cil_symtab_datum_remove_node(struct cil_symtab_datum *datum, struct cil_tree_node *node)
+{
+ if (datum && datum->nodes != NULL) {
+ cil_list_remove(datum->nodes, CIL_NODE, node, 0);
+ if (datum->nodes->head == NULL) {
+ cil_symtab_datum_destroy(datum);
+ }
+ }
+}
+
+/* This both initializes the datum and inserts it into the symtab.
+ Note that cil_symtab_datum_destroy() is the analog to the initializer portion */
+int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node)
+{
+ int rc = hashtab_insert(symtab->table, key, (hashtab_datum_t)datum);
+ if (rc == SEPOL_OK) {
+ datum->name = key;
+ datum->fqn = key;
+ datum->symtab = symtab;
+ cil_list_append(datum->nodes, CIL_NODE, node);
+ } else if (rc == SEPOL_EEXIST) {
+ cil_list_append(datum->nodes, CIL_NODE, node);
+ } else {
+ cil_symtab_error("Failed to insert datum into hashtab\n");
+ }
+
+ return rc;
+}
+
+void cil_symtab_remove_datum(struct cil_symtab_datum *datum)
+{
+ symtab_t *symtab = datum->symtab;
+
+ if (symtab == NULL) {
+ return;
+ }
+
+ hashtab_remove(symtab->table, datum->name, NULL, NULL);
+ datum->symtab = NULL;
+}
+
+int cil_symtab_get_datum(symtab_t *symtab, char *key, struct cil_symtab_datum **datum)
+{
+ *datum = (struct cil_symtab_datum*)hashtab_search(symtab->table, (hashtab_key_t)key);
+ if (*datum == NULL) {
+ return SEPOL_ENOENT;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_symtab_map(symtab_t *symtab,
+ int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args),
+ void *args)
+{
+ return hashtab_map(symtab->table, apply, args);
+}
+
+static int __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
+{
+ struct cil_symtab_datum *datum = d;
+ datum->symtab = NULL;
+ return SEPOL_OK;
+}
+
+void cil_symtab_destroy(symtab_t *symtab)
+{
+ if (symtab->table != NULL){
+ cil_symtab_map(symtab, __cil_symtab_destroy_helper, NULL);
+ hashtab_destroy(symtab->table);
+ symtab->table = NULL;
+ }
+}
+
+void cil_complex_symtab_hash(struct cil_complex_symtab_key *ckey, int mask, intptr_t *hash)
+{
+ intptr_t sum = ckey->key1 + ckey->key2 + ckey->key3 + ckey->key4;
+ *hash = (intptr_t)((sum >> 2) & mask);
+}
+
+void cil_complex_symtab_init(struct cil_complex_symtab *symtab, unsigned int size)
+{
+ symtab->htable = cil_calloc(size, sizeof(struct cil_complex_symtab *));
+
+ symtab->nelems = 0;
+ symtab->nslots = size;
+ symtab->mask = size - 1;
+}
+
+int cil_complex_symtab_insert(struct cil_complex_symtab *symtab,
+ struct cil_complex_symtab_key *ckey,
+ struct cil_complex_symtab_datum *datum)
+{
+ intptr_t hash;
+ struct cil_complex_symtab_node *node = NULL;
+ struct cil_complex_symtab_node *prev = NULL;
+ struct cil_complex_symtab_node *curr = NULL;
+
+ node = cil_malloc(sizeof(*node));
+ memset(node, 0, sizeof(*node));
+
+ node->ckey = ckey;
+ node->datum = datum;
+
+ cil_complex_symtab_hash(ckey, symtab->mask, &hash);
+
+ for (prev = NULL, curr = symtab->htable[hash]; curr != NULL;
+ prev = curr, curr = curr->next) {
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 == curr->ckey->key3 &&
+ ckey->key4 == curr->ckey->key4) {
+ return SEPOL_EEXIST;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 < curr->ckey->key2) {
+ break;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 < curr->ckey->key3) {
+ break;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 == curr->ckey->key3 &&
+ ckey->key4 < curr->ckey->key4) {
+ break;
+ }
+ }
+
+ if (prev != NULL) {
+ node->next = prev->next;
+ prev->next = node;
+ } else {
+ node->next = symtab->htable[hash];
+ symtab->htable[hash] = node;
+ }
+
+ symtab->nelems++;
+
+ return SEPOL_OK;
+}
+
+void cil_complex_symtab_search(struct cil_complex_symtab *symtab,
+ struct cil_complex_symtab_key *ckey,
+ struct cil_complex_symtab_datum **out)
+{
+ intptr_t hash;
+ struct cil_complex_symtab_node *curr = NULL;
+
+ cil_complex_symtab_hash(ckey, symtab->mask, &hash);
+ for (curr = symtab->htable[hash]; curr != NULL; curr = curr->next) {
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 == curr->ckey->key3 &&
+ ckey->key4 == curr->ckey->key4) {
+ *out = curr->datum;
+ return;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 < curr->ckey->key2) {
+ break;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 < curr->ckey->key3) {
+ break;
+ }
+
+ if (ckey->key1 == curr->ckey->key1 &&
+ ckey->key2 == curr->ckey->key2 &&
+ ckey->key3 == curr->ckey->key3 &&
+ ckey->key4 < curr->ckey->key4) {
+ break;
+ }
+ }
+
+ *out = NULL;
+}
+
+void cil_complex_symtab_destroy(struct cil_complex_symtab *symtab)
+{
+ struct cil_complex_symtab_node *curr = NULL;
+ struct cil_complex_symtab_node *temp = NULL;
+ unsigned int i;
+
+ if (symtab == NULL) {
+ return;
+ }
+
+ for (i = 0; i < symtab->nslots; i++) {
+ curr = symtab->htable[i];
+ while (curr != NULL) {
+ temp = curr;
+ curr = curr->next;
+ free(temp);
+ }
+ symtab->htable[i] = NULL;
+ }
+ free(symtab->htable);
+ symtab->htable = NULL;
+ symtab->nelems = 0;
+ symtab->nslots = 0;
+ symtab->mask = 0;
+}
diff --git a/libsepol/cil/src/cil_symtab.h b/libsepol/cil/src/cil_symtab.h
new file mode 100644
index 0000000..efb63e7
--- /dev/null
+++ b/libsepol/cil/src/cil_symtab.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef __CIL_SYMTAB_H_
+#define __CIL_SYMTAB_H_
+
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/hashtab.h>
+
+#include "cil_tree.h"
+
+struct cil_symtab_datum {
+ struct cil_list *nodes;
+ char *name;
+ char *fqn;
+ symtab_t *symtab;
+};
+
+#define DATUM(d) ((struct cil_symtab_datum *)(d))
+#define NODE(n) ((struct cil_tree_node *)(DATUM(n)->nodes->head->data))
+#define FLAVOR(f) (NODE(f)->flavor)
+
+struct cil_complex_symtab_key {
+ intptr_t key1;
+ intptr_t key2;
+ intptr_t key3;
+ intptr_t key4;
+};
+
+struct cil_complex_symtab_datum {
+ void *data;
+};
+
+struct cil_complex_symtab_node {
+ struct cil_complex_symtab_key *ckey;
+ struct cil_complex_symtab_datum *datum;
+ struct cil_complex_symtab_node *next;
+};
+
+struct cil_complex_symtab {
+ struct cil_complex_symtab_node **htable;
+ uint32_t nelems;
+ uint32_t nslots;
+ uint32_t mask;
+};
+
+void cil_symtab_init(symtab_t *symtab, unsigned int size);
+void cil_symtab_datum_init(struct cil_symtab_datum *datum);
+void cil_symtab_datum_destroy(struct cil_symtab_datum *datum);
+void cil_symtab_datum_remove_node(struct cil_symtab_datum *datum, struct cil_tree_node *node);
+int cil_symtab_insert(symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node);
+void cil_symtab_remove_datum(struct cil_symtab_datum *datum);
+int cil_symtab_get_datum(symtab_t *symtab, char *key, struct cil_symtab_datum **datum);
+int cil_symtab_map(symtab_t *symtab,
+ int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args),
+ void *args);
+void cil_symtab_destroy(symtab_t *symtab);
+void cil_complex_symtab_init(struct cil_complex_symtab *symtab, unsigned int size);
+int cil_complex_symtab_insert(struct cil_complex_symtab *symtab, struct cil_complex_symtab_key *ckey, struct cil_complex_symtab_datum *datum);
+void cil_complex_symtab_search(struct cil_complex_symtab *symtab, struct cil_complex_symtab_key *ckey, struct cil_complex_symtab_datum **out);
+void cil_complex_symtab_destroy(struct cil_complex_symtab *symtab);
+
+#endif
diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
new file mode 100644
index 0000000..9ff9d4b
--- /dev/null
+++ b/libsepol/cil/src/cil_tree.c
@@ -0,0 +1,1749 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <sepol/policydb/conditional.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_parser.h"
+#include "cil_strpool.h"
+
+void cil_tree_print_perms_list(struct cil_tree_node *current_perm);
+void cil_tree_print_classperms(struct cil_classperms *cp);
+void cil_tree_print_level(struct cil_level *level);
+void cil_tree_print_levelrange(struct cil_levelrange *lvlrange);
+void cil_tree_print_context(struct cil_context *context);
+void cil_tree_print_expr_tree(struct cil_tree_node *expr_root);
+void cil_tree_print_constrain(struct cil_constrain *cons);
+void cil_tree_print_node(struct cil_tree_node *node);
+
+__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_error(const char* msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ cil_vlog(CIL_ERR, msg, ap);
+ va_end(ap);
+ exit(1);
+}
+
+struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil)
+{
+ if (!node) {
+ return NULL;
+ }
+
+ node = node->parent;
+
+ while (node) {
+ if (node->flavor == CIL_NODE && node->data == NULL) {
+ if (node->cl_head->data == CIL_KEY_SRC_INFO) {
+ /* Parse Tree */
+ *path = node->cl_head->next->next->data;
+ *is_cil = (node->cl_head->next->data == CIL_KEY_SRC_CIL);
+ return node;
+ }
+ node = node->parent;
+ } else if (node->flavor == CIL_SRC_INFO) {
+ /* AST */
+ struct cil_src_info *info = node->data;
+ *path = info->path;
+ *is_cil = info->is_cil;
+ return node;
+ } else {
+ if (node->flavor == CIL_CALL) {
+ struct cil_call *call = node->data;
+ node = NODE(call->macro);
+ } else if (node->flavor == CIL_BLOCKINHERIT) {
+ struct cil_blockinherit *inherit = node->data;
+ node = NODE(inherit->block);
+ } else {
+ node = node->parent;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+char *cil_tree_get_cil_path(struct cil_tree_node *node)
+{
+ char *path = NULL;
+ int is_cil;
+
+ while (node) {
+ node = cil_tree_get_next_path(node, &path, &is_cil);
+ if (node && is_cil) {
+ return path;
+ }
+ }
+
+ return NULL;
+}
+
+__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ cil_vlog(lvl, msg, ap);
+ va_end(ap);
+
+ if (node) {
+ char *path = NULL;
+ int is_cil;
+ unsigned hll_line = node->hll_line;
+
+ path = cil_tree_get_cil_path(node);
+
+ if (path != NULL) {
+ cil_log(lvl, " at %s:%d", path, node->line);
+ }
+
+ while (node) {
+ node = cil_tree_get_next_path(node, &path, &is_cil);
+ if (node && !is_cil) {
+ cil_log(lvl," from %s:%d", path, hll_line);
+ path = NULL;
+ hll_line = node->hll_line;
+ }
+ }
+ }
+
+ cil_log(lvl,"\n");
+}
+
+int cil_tree_init(struct cil_tree **tree)
+{
+ struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree));
+
+ cil_tree_node_init(&new_tree->root);
+
+ *tree = new_tree;
+
+ return SEPOL_OK;
+}
+
+void cil_tree_destroy(struct cil_tree **tree)
+{
+ if (tree == NULL || *tree == NULL) {
+ return;
+ }
+
+ cil_tree_subtree_destroy((*tree)->root);
+ free(*tree);
+ *tree = NULL;
+}
+
+void cil_tree_subtree_destroy(struct cil_tree_node *node)
+{
+ cil_tree_children_destroy(node);
+ cil_tree_node_destroy(&node);
+}
+
+void cil_tree_children_destroy(struct cil_tree_node *node)
+{
+ struct cil_tree_node *start_node = node;
+ struct cil_tree_node *next = NULL;
+
+ if (node == NULL) {
+ return;
+ }
+
+ if (node->cl_head != NULL) {
+ node = node->cl_head;
+ }
+
+ while (node != start_node) {
+ if (node->cl_head != NULL){
+ next = node->cl_head;
+ } else {
+ if (node->next == NULL) {
+ next = node->parent;
+ if (node->parent != NULL) {
+ node->parent->cl_head = NULL;
+ }
+ cil_tree_node_destroy(&node);
+ } else {
+ next = node->next;
+ cil_tree_node_destroy(&node);
+ }
+ }
+ node = next;
+ }
+}
+
+void cil_tree_node_init(struct cil_tree_node **node)
+{
+ struct cil_tree_node *new_node = cil_malloc(sizeof(*new_node));
+ new_node->cl_head = NULL;
+ new_node->cl_tail = NULL;
+ new_node->parent = NULL;
+ new_node->data = NULL;
+ new_node->next = NULL;
+ new_node->flavor = CIL_ROOT;
+ new_node->line = 0;
+ new_node->hll_line = 0;
+
+ *node = new_node;
+}
+
+void cil_tree_node_destroy(struct cil_tree_node **node)
+{
+ struct cil_symtab_datum *datum;
+
+ if (node == NULL || *node == NULL) {
+ return;
+ }
+
+ if ((*node)->flavor >= CIL_MIN_DECLARATIVE) {
+ datum = (*node)->data;
+ cil_symtab_datum_remove_node(datum, *node);
+ if (datum->nodes == NULL) {
+ cil_destroy_data(&(*node)->data, (*node)->flavor);
+ }
+ } else {
+ cil_destroy_data(&(*node)->data, (*node)->flavor);
+ }
+ free(*node);
+ *node = NULL;
+}
+
+/* Perform depth-first walk of the tree
+ Parameters:
+ start_node: root node to start walking from
+ process_node: function to call when visiting a node
+ Takes parameters:
+ node: node being visited
+ finished: boolean indicating to the tree walker that it should move on from this branch
+ extra_args: additional data
+ first_child: Function to call before entering list of children
+ Takes parameters:
+ node: node of first child
+ extra args: additional data
+ last_child: Function to call when finished with the last child of a node's children
+ extra_args: any additional data to be passed to the helper functions
+*/
+
+int cil_tree_walk_core(struct cil_tree_node *node,
+ int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args),
+ int (*first_child)(struct cil_tree_node *node, void *extra_args),
+ int (*last_child)(struct cil_tree_node *node, void *extra_args),
+ void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ while (node) {
+ uint32_t finished = CIL_TREE_SKIP_NOTHING;
+
+ if (process_node != NULL) {
+ rc = (*process_node)(node, &finished, extra_args);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_INFO, "Problem");
+ return rc;
+ }
+ }
+
+ if (finished & CIL_TREE_SKIP_NEXT) {
+ return SEPOL_OK;
+ }
+
+ if (node->cl_head != NULL && !(finished & CIL_TREE_SKIP_HEAD)) {
+ rc = cil_tree_walk(node, process_node, first_child, last_child, extra_args);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+ }
+
+ node = node->next;
+ }
+
+ return SEPOL_OK;
+}
+
+int cil_tree_walk(struct cil_tree_node *node,
+ int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args),
+ int (*first_child)(struct cil_tree_node *node, void *extra_args),
+ int (*last_child)(struct cil_tree_node *node, void *extra_args),
+ void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ if (!node || !node->cl_head) {
+ return SEPOL_OK;
+ }
+
+ if (first_child != NULL) {
+ rc = (*first_child)(node->cl_head, extra_args);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_INFO, "Problem");
+ return rc;
+ }
+ }
+
+ rc = cil_tree_walk_core(node->cl_head, process_node, first_child, last_child, extra_args);
+ if (rc != SEPOL_OK) {
+ return rc;
+ }
+
+ if (last_child != NULL) {
+ rc = (*last_child)(node->cl_tail, extra_args);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_INFO, "Problem");
+ return rc;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+
+/* Copied from cil_policy.c, but changed to prefix -- Need to refactor */
+static int cil_expr_to_string(struct cil_list *expr, char **out)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ char *stack[COND_EXPR_MAXDEPTH] = {};
+ int pos = 0;
+
+ cil_list_for_each(curr, expr) {
+ if (pos > COND_EXPR_MAXDEPTH) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ switch (curr->flavor) {
+ case CIL_LIST:
+ rc = cil_expr_to_string(curr->data, &stack[pos]);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ pos++;
+ break;
+ case CIL_STRING:
+ stack[pos] = curr->data;
+ pos++;
+ break;
+ case CIL_DATUM:
+ stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
+ pos++;
+ break;
+ case CIL_OP: {
+ int len;
+ char *expr_str;
+ enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
+ char *op_str = NULL;
+
+ if (pos == 0) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ switch (op_flavor) {
+ case CIL_AND:
+ op_str = CIL_KEY_AND;
+ break;
+ case CIL_OR:
+ op_str = CIL_KEY_OR;
+ break;
+ case CIL_NOT:
+ op_str = CIL_KEY_NOT;
+ break;
+ case CIL_ALL:
+ op_str = CIL_KEY_ALL;
+ break;
+ case CIL_EQ:
+ op_str = CIL_KEY_EQ;
+ break;
+ case CIL_NEQ:
+ op_str = CIL_KEY_NEQ;
+ break;
+ case CIL_XOR:
+ op_str = CIL_KEY_XOR;
+ break;
+ case CIL_RANGE:
+ op_str = CIL_KEY_RANGE;
+ break;
+ case CIL_CONS_DOM:
+ op_str = CIL_KEY_CONS_DOM;
+ break;
+ case CIL_CONS_DOMBY:
+ op_str = CIL_KEY_CONS_DOMBY;
+ break;
+ case CIL_CONS_INCOMP:
+ op_str = CIL_KEY_CONS_INCOMP;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown operator in expression\n");
+ goto exit;
+ break;
+ }
+ if (op_flavor == CIL_NOT) {
+ len = strlen(stack[pos-1]) + strlen(op_str) + 4;
+ expr_str = cil_malloc(len);
+ snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
+ free(stack[pos-1]);
+ stack[pos-1] = NULL;
+ pos--;
+ } else {
+ if (pos < 2) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
+ expr_str = cil_malloc(len);
+ snprintf(expr_str, len, "(%s %s %s)", op_str, stack[pos-1], stack[pos-2]);
+ free(stack[pos-2]);
+ free(stack[pos-1]);
+ stack[pos-2] = NULL;
+ stack[pos-1] = NULL;
+ pos -= 2;
+ }
+ stack[pos] = expr_str;
+ pos++;
+ break;
+ }
+ case CIL_CONS_OPERAND: {
+ enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
+ char *operand_str = NULL;
+ switch (operand_flavor) {
+ case CIL_CONS_U1:
+ operand_str = CIL_KEY_CONS_U1;
+ break;
+ case CIL_CONS_U2:
+ operand_str = CIL_KEY_CONS_U2;
+ break;
+ case CIL_CONS_U3:
+ operand_str = CIL_KEY_CONS_U3;
+ break;
+ case CIL_CONS_T1:
+ operand_str = CIL_KEY_CONS_T1;
+ break;
+ case CIL_CONS_T2:
+ operand_str = CIL_KEY_CONS_T2;
+ break;
+ case CIL_CONS_T3:
+ operand_str = CIL_KEY_CONS_T3;
+ break;
+ case CIL_CONS_R1:
+ operand_str = CIL_KEY_CONS_R1;
+ break;
+ case CIL_CONS_R2:
+ operand_str = CIL_KEY_CONS_R2;
+ break;
+ case CIL_CONS_R3:
+ operand_str = CIL_KEY_CONS_R3;
+ break;
+ case CIL_CONS_L1:
+ operand_str = CIL_KEY_CONS_L1;
+ break;
+ case CIL_CONS_L2:
+ operand_str = CIL_KEY_CONS_L2;
+ break;
+ case CIL_CONS_H1:
+ operand_str = CIL_KEY_CONS_H1;
+ break;
+ case CIL_CONS_H2:
+ operand_str = CIL_KEY_CONS_H2;
+ break;
+ default:
+ cil_log(CIL_ERR, "Unknown operand in expression\n");
+ goto exit;
+ break;
+ }
+ stack[pos] = operand_str;
+ pos++;
+ break;
+ }
+ default:
+ cil_log(CIL_ERR, "Unknown flavor in expression\n");
+ goto exit;
+ break;
+ }
+ }
+
+ *out = stack[0];
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+void cil_tree_print_expr(struct cil_list *datum_expr, struct cil_list *str_expr)
+{
+ char *expr_str;
+
+ cil_log(CIL_INFO, "(");
+
+ if (datum_expr != NULL) {
+ cil_expr_to_string(datum_expr, &expr_str);
+ } else {
+ cil_expr_to_string(str_expr, &expr_str);
+ }
+
+ cil_log(CIL_INFO, "%s)", expr_str);
+ free(expr_str);
+}
+
+void cil_tree_print_perms_list(struct cil_tree_node *current_perm)
+{
+ while (current_perm != NULL) {
+ if (current_perm->flavor == CIL_PERM) {
+ cil_log(CIL_INFO, " %s", ((struct cil_perm *)current_perm->data)->datum.name);
+ } else if (current_perm->flavor == CIL_MAP_PERM) {
+ cil_log(CIL_INFO, " %s", ((struct cil_perm*)current_perm->data)->datum.name);
+ } else {
+ cil_log(CIL_INFO, "\n\n perms list contained unexpected data type: %d\n", current_perm->flavor);
+ break;
+ }
+ current_perm = current_perm->next;
+ }
+}
+
+void cil_tree_print_cats(struct cil_cats *cats)
+{
+ cil_tree_print_expr(cats->datum_expr, cats->str_expr);
+}
+
+void cil_tree_print_perm_strs(struct cil_list *perm_strs)
+{
+ struct cil_list_item *curr;
+
+ if (perm_strs == NULL) {
+ return;
+ }
+
+ cil_log(CIL_INFO, " (");
+
+ cil_list_for_each(curr, perm_strs) {
+ cil_log(CIL_INFO, " %s", (char*)curr->data);
+ }
+
+ cil_log(CIL_INFO, " )");
+}
+
+
+void cil_tree_print_classperms(struct cil_classperms *cp)
+{
+ if (cp == NULL) {
+ return;
+ }
+
+ cil_log(CIL_INFO, " class: %s", cp->class_str);
+ cil_log(CIL_INFO, ", perm_strs:");
+ cil_tree_print_perm_strs(cp->perm_strs);
+}
+
+void cil_tree_print_classperms_set(struct cil_classperms_set *cp_set)
+{
+ if (cp_set == NULL) {
+ return;
+ }
+
+ cil_log(CIL_INFO, " %s", cp_set->set_str);
+}
+
+void cil_tree_print_classperms_list(struct cil_list *cp_list)
+{
+ struct cil_list_item *i;
+
+ if (cp_list == NULL) {
+ return;
+ }
+
+ cil_list_for_each(i, cp_list) {
+ if (i->flavor == CIL_CLASSPERMS) {
+ cil_tree_print_classperms(i->data);
+ } else {
+ cil_tree_print_classperms_set(i->data);
+ }
+ }
+}
+
+void cil_tree_print_level(struct cil_level *level)
+{
+ if (level->sens != NULL) {
+ cil_log(CIL_INFO, " %s", level->sens->datum.name);
+ } else if (level->sens_str != NULL) {
+ cil_log(CIL_INFO, " %s", level->sens_str);
+ }
+
+ cil_tree_print_cats(level->cats);
+
+ return;
+}
+
+void cil_tree_print_levelrange(struct cil_levelrange *lvlrange)
+{
+ cil_log(CIL_INFO, " (");
+ if (lvlrange->low != NULL) {
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_level(lvlrange->low);
+ cil_log(CIL_INFO, " )");
+ } else if (lvlrange->low_str != NULL) {
+ cil_log(CIL_INFO, " %s", lvlrange->low_str);
+ }
+
+ if (lvlrange->high != NULL) {
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_level(lvlrange->high);
+ cil_log(CIL_INFO, " )");
+ } else if (lvlrange->high_str != NULL) {
+ cil_log(CIL_INFO, " %s", lvlrange->high_str);
+ }
+ cil_log(CIL_INFO, " )");
+}
+
+void cil_tree_print_context(struct cil_context *context)
+{
+ cil_log(CIL_INFO, " (");
+ if (context->user != NULL) {
+ cil_log(CIL_INFO, " %s", context->user->datum.name);
+ } else if (context->user_str != NULL) {
+ cil_log(CIL_INFO, " %s", context->user_str);
+ }
+
+ if (context->role != NULL) {
+ cil_log(CIL_INFO, " %s", context->role->datum.name);
+ } else if (context->role_str != NULL) {
+ cil_log(CIL_INFO, " %s", context->role_str);
+ }
+
+ if (context->type != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)context->type)->name);
+ } else if (context->type_str != NULL) {
+ cil_log(CIL_INFO, " %s", context->type_str);
+ }
+
+ if (context->range != NULL) {
+ cil_tree_print_levelrange(context->range);
+ } else if (context->range_str != NULL) {
+ cil_log(CIL_INFO, " %s", context->range_str);
+ }
+
+ cil_log(CIL_INFO, " )");
+
+ return;
+}
+
+void cil_tree_print_constrain(struct cil_constrain *cons)
+{
+ cil_tree_print_classperms_list(cons->classperms);
+
+ cil_tree_print_expr(cons->datum_expr, cons->str_expr);
+
+ cil_log(CIL_INFO, "\n");
+}
+
+void cil_tree_print_node(struct cil_tree_node *node)
+{
+ if (node->data == NULL) {
+ cil_log(CIL_INFO, "FLAVOR: %d", node->flavor);
+ return;
+ } else {
+ switch( node->flavor ) {
+ case CIL_BLOCK: {
+ struct cil_block *block = node->data;
+ cil_log(CIL_INFO, "BLOCK: %s\n", block->datum.name);
+ return;
+ }
+ case CIL_BLOCKINHERIT: {
+ struct cil_blockinherit *inherit = node->data;
+ cil_log(CIL_INFO, "BLOCKINHERIT: %s\n", inherit->block_str);
+ return;
+ }
+ case CIL_BLOCKABSTRACT: {
+ struct cil_blockabstract *abstract = node->data;
+ cil_log(CIL_INFO, "BLOCKABSTRACT: %s\n", abstract->block_str);
+ return;
+ }
+ case CIL_IN: {
+ struct cil_in *in = node->data;
+ cil_log(CIL_INFO, "IN: %s\n", in->block_str);
+ return;
+ }
+ case CIL_USER: {
+ struct cil_user *user = node->data;
+ cil_log(CIL_INFO, "USER: %s\n", user->datum.name);
+ return;
+ }
+ case CIL_TYPE: {
+ struct cil_type *type = node->data;
+ cil_log(CIL_INFO, "TYPE: %s\n", type->datum.name);
+ return;
+ }
+ case CIL_TYPEATTRIBUTESET: {
+ struct cil_typeattributeset *attr = node->data;
+
+ cil_log(CIL_INFO, "(TYPEATTRIBUTESET %s ", attr->attr_str);
+
+ cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_TYPEATTRIBUTE: {
+ struct cil_typeattribute *attr = node->data;
+ cil_log(CIL_INFO, "TYPEATTRIBUTE: %s\n", attr->datum.name);
+ return;
+ }
+ case CIL_ROLE: {
+ struct cil_role *role = node->data;
+ cil_log(CIL_INFO, "ROLE: %s\n", role->datum.name);
+ return;
+ }
+ case CIL_USERROLE: {
+ struct cil_userrole *userrole = node->data;
+ cil_log(CIL_INFO, "USERROLE:");
+ struct cil_symtab_datum *datum = NULL;
+
+ if (userrole->user != NULL) {
+ datum = userrole->user;
+ cil_log(CIL_INFO, " %s", datum->name);
+ } else if (userrole->user_str != NULL) {
+ cil_log(CIL_INFO, " %s", userrole->user_str);
+ }
+
+ if (userrole->role != NULL) {
+ datum = userrole->role;
+ cil_log(CIL_INFO, " %s", datum->name);
+ } else if (userrole->role_str != NULL) {
+ cil_log(CIL_INFO, " %s", userrole->role_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_USERLEVEL: {
+ struct cil_userlevel *usrlvl = node->data;
+ cil_log(CIL_INFO, "USERLEVEL:");
+
+ if (usrlvl->user_str != NULL) {
+ cil_log(CIL_INFO, " %s", usrlvl->user_str);
+ }
+
+ if (usrlvl->level != NULL) {
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_level(usrlvl->level);
+ cil_log(CIL_INFO, " )");
+ } else if (usrlvl->level_str != NULL) {
+ cil_log(CIL_INFO, " %s", usrlvl->level_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_USERRANGE: {
+ struct cil_userrange *userrange = node->data;
+ cil_log(CIL_INFO, "USERRANGE:");
+
+ if (userrange->user_str != NULL) {
+ cil_log(CIL_INFO, " %s", userrange->user_str);
+ }
+
+ if (userrange->range != NULL) {
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_levelrange(userrange->range);
+ cil_log(CIL_INFO, " )");
+ } else if (userrange->range_str != NULL) {
+ cil_log(CIL_INFO, " %s", userrange->range_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_USERBOUNDS: {
+ struct cil_bounds *bnds = node->data;
+ cil_log(CIL_INFO, "USERBOUNDS: user: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+ return;
+ }
+ case CIL_ROLETYPE: {
+ struct cil_roletype *roletype = node->data;
+ struct cil_symtab_datum *datum = NULL;
+ cil_log(CIL_INFO, "ROLETYPE:");
+
+ if (roletype->role != NULL) {
+ datum = roletype->role;
+ cil_log(CIL_INFO, " %s", datum->name);
+ } else if (roletype->role_str != NULL) {
+ cil_log(CIL_INFO, " %s", roletype->role_str);
+ }
+
+ if (roletype->type != NULL) {
+ datum = roletype->type;
+ cil_log(CIL_INFO, " %s", datum->name);
+ } else if (roletype->type_str != NULL) {
+ cil_log(CIL_INFO, " %s", roletype->type_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_ROLETRANSITION: {
+ struct cil_roletransition *roletrans = node->data;
+ cil_log(CIL_INFO, "ROLETRANSITION:");
+
+ if (roletrans->src != NULL) {
+ cil_log(CIL_INFO, " %s", roletrans->src->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", roletrans->src_str);
+ }
+
+ if (roletrans->tgt != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)roletrans->tgt)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", roletrans->tgt_str);
+ }
+
+ if (roletrans->obj != NULL) {
+ cil_log(CIL_INFO, " %s", roletrans->obj->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", roletrans->obj_str);
+ }
+
+ if (roletrans->result != NULL) {
+ cil_log(CIL_INFO, " %s\n", roletrans->result->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s\n", roletrans->result_str);
+ }
+
+ return;
+ }
+ case CIL_ROLEALLOW: {
+ struct cil_roleallow *roleallow = node->data;
+ cil_log(CIL_INFO, "ROLEALLOW:");
+
+ if (roleallow->src != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->src)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", roleallow->src_str);
+ }
+
+ if (roleallow->tgt != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)roleallow->tgt)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", roleallow->tgt_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_ROLEATTRIBUTESET: {
+ struct cil_roleattributeset *attr = node->data;
+
+ cil_log(CIL_INFO, "(ROLEATTRIBUTESET %s ", attr->attr_str);
+
+ cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_ROLEATTRIBUTE: {
+ struct cil_roleattribute *attr = node->data;
+ cil_log(CIL_INFO, "ROLEATTRIBUTE: %s\n", attr->datum.name);
+ return;
+ }
+ case CIL_USERATTRIBUTESET: {
+ struct cil_userattributeset *attr = node->data;
+
+ cil_log(CIL_INFO, "(USERATTRIBUTESET %s ", attr->attr_str);
+
+ cil_tree_print_expr(attr->datum_expr, attr->str_expr);
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_USERATTRIBUTE: {
+ struct cil_userattribute *attr = node->data;
+ cil_log(CIL_INFO, "USERATTRIBUTE: %s\n", attr->datum.name);
+ return;
+ }
+ case CIL_ROLEBOUNDS: {
+ struct cil_bounds *bnds = node->data;
+ cil_log(CIL_INFO, "ROLEBOUNDS: role: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+ return;
+ }
+ case CIL_CLASS: {
+ struct cil_class *cls = node->data;
+ cil_log(CIL_INFO, "CLASS: %s ", cls->datum.name);
+
+ if (cls->common != NULL) {
+ cil_log(CIL_INFO, "inherits: %s ", cls->common->datum.name);
+ }
+ cil_log(CIL_INFO, "(");
+
+ cil_tree_print_perms_list(node->cl_head);
+
+ cil_log(CIL_INFO, " )");
+ return;
+ }
+ case CIL_CLASSORDER: {
+ struct cil_classorder *classorder = node->data;
+ struct cil_list_item *class;
+
+ if (classorder->class_list_str == NULL) {
+ cil_log(CIL_INFO, "CLASSORDER: ()\n");
+ return;
+ }
+
+ cil_log(CIL_INFO, "CLASSORDER: (");
+ cil_list_for_each(class, classorder->class_list_str) {
+ cil_log(CIL_INFO, " %s", (char*)class->data);
+ }
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_COMMON: {
+ struct cil_class *common = node->data;
+ cil_log(CIL_INFO, "COMMON: %s (", common->datum.name);
+
+ cil_tree_print_perms_list(node->cl_head);
+
+ cil_log(CIL_INFO, " )");
+ return;
+ }
+ case CIL_CLASSCOMMON: {
+ struct cil_classcommon *clscom = node->data;
+
+ cil_log(CIL_INFO, "CLASSCOMMON: class: %s, common: %s\n", clscom->class_str, clscom->common_str);
+
+ return;
+ }
+ case CIL_CLASSPERMISSION: {
+ struct cil_classpermission *cp = node->data;
+
+ cil_log(CIL_INFO, "CLASSPERMISSION: %s", cp->datum.name);
+
+ cil_log(CIL_INFO, "\n");
+
+ return;
+ }
+ case CIL_CLASSPERMISSIONSET: {
+ struct cil_classpermissionset *cps = node->data;
+
+ cil_log(CIL_INFO, "CLASSPERMISSIONSET: %s", cps->set_str);
+
+ cil_tree_print_classperms_list(cps->classperms);
+
+ cil_log(CIL_INFO, "\n");
+
+ return;
+ }
+ case CIL_MAP_CLASS: {
+ struct cil_class *cm = node->data;
+ cil_log(CIL_INFO, "MAP_CLASS: %s", cm->datum.name);
+
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_perms_list(node->cl_head);
+ cil_log(CIL_INFO, " )\n");
+
+ return;
+ }
+ case CIL_MAP_PERM: {
+ struct cil_perm *cmp = node->data;
+
+ cil_log(CIL_INFO, "MAP_PERM: %s", cmp->datum.name);
+
+ if (cmp->classperms == NULL) {
+ cil_log(CIL_INFO, " perms: ()");
+ return;
+ }
+
+ cil_log(CIL_INFO, " kernel class perms: (");
+
+ cil_tree_print_classperms_list(cmp->classperms);
+
+ cil_log(CIL_INFO, " )\n");
+
+ return;
+ }
+ case CIL_CLASSMAPPING: {
+ struct cil_classmapping *mapping = node->data;
+
+ cil_log(CIL_INFO, "CLASSMAPPING: map class: %s, map perm: %s,", mapping->map_class_str, mapping->map_perm_str);
+
+ cil_log(CIL_INFO, " (");
+
+ cil_tree_print_classperms_list(mapping->classperms);
+
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_BOOL: {
+ struct cil_bool *boolean = node->data;
+ cil_log(CIL_INFO, "BOOL: %s, value: %d\n", boolean->datum.name, boolean->value);
+ return;
+ }
+ case CIL_TUNABLE: {
+ struct cil_tunable *tunable = node->data;
+ cil_log(CIL_INFO, "TUNABLE: %s, value: %d\n", tunable->datum.name, tunable->value);
+ return;
+ }
+ case CIL_BOOLEANIF: {
+ struct cil_booleanif *bif = node->data;
+
+ cil_log(CIL_INFO, "(BOOLEANIF ");
+
+ cil_tree_print_expr(bif->datum_expr, bif->str_expr);
+
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_TUNABLEIF: {
+ struct cil_tunableif *tif = node->data;
+
+ cil_log(CIL_INFO, "(TUNABLEIF ");
+
+ cil_tree_print_expr(tif->datum_expr, tif->str_expr);
+
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_CONDBLOCK: {
+ struct cil_condblock *cb = node->data;
+ if (cb->flavor == CIL_CONDTRUE) {
+ cil_log(CIL_INFO, "true\n");
+ } else if (cb->flavor == CIL_CONDFALSE) {
+ cil_log(CIL_INFO, "false\n");
+ }
+ return;
+ }
+ case CIL_ALL:
+ cil_log(CIL_INFO, "all");
+ return;
+ case CIL_AND:
+ cil_log(CIL_INFO, "&&");
+ return;
+ case CIL_OR:
+ cil_log(CIL_INFO, "|| ");
+ return;
+ case CIL_NOT:
+ cil_log(CIL_INFO, "!");
+ return;
+ case CIL_EQ:
+ cil_log(CIL_INFO, "==");
+ return;
+ case CIL_NEQ:
+ cil_log(CIL_INFO, "!=");
+ return;
+ case CIL_TYPEALIAS: {
+ struct cil_alias *alias = node->data;
+ cil_log(CIL_INFO, "TYPEALIAS: %s\n", alias->datum.name);
+ return;
+ }
+ case CIL_TYPEALIASACTUAL: {
+ struct cil_aliasactual *aliasactual = node->data;
+ cil_log(CIL_INFO, "TYPEALIASACTUAL: type: %s, alias: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+ return;
+ }
+ case CIL_TYPEBOUNDS: {
+ struct cil_bounds *bnds = node->data;
+ cil_log(CIL_INFO, "TYPEBOUNDS: type: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
+ return;
+ }
+ case CIL_TYPEPERMISSIVE: {
+ struct cil_typepermissive *typeperm = node->data;
+
+ if (typeperm->type != NULL) {
+ cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", ((struct cil_symtab_datum *)typeperm->type)->name);
+ } else {
+ cil_log(CIL_INFO, "TYPEPERMISSIVE: %s\n", typeperm->type_str);
+ }
+
+ return;
+ }
+ case CIL_NAMETYPETRANSITION: {
+ struct cil_nametypetransition *nametypetrans = node->data;
+ cil_log(CIL_INFO, "TYPETRANSITION:");
+
+ if (nametypetrans->src != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->src)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", nametypetrans->src_str);
+ }
+
+ if (nametypetrans->tgt != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->tgt)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", nametypetrans->tgt_str);
+ }
+
+ if (nametypetrans->obj != NULL) {
+ cil_log(CIL_INFO, " %s", nametypetrans->obj->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", nametypetrans->obj_str);
+ }
+
+ cil_log(CIL_INFO, " %s\n", nametypetrans->name_str);
+
+ if (nametypetrans->result != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)nametypetrans->result)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", nametypetrans->result_str);
+ }
+
+ return;
+ }
+ case CIL_RANGETRANSITION: {
+ struct cil_rangetransition *rangetrans = node->data;
+ cil_log(CIL_INFO, "RANGETRANSITION:");
+
+ if (rangetrans->src != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->src)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rangetrans->src_str);
+ }
+
+ if (rangetrans->exec != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rangetrans->exec)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rangetrans->exec_str);
+ }
+
+ if (rangetrans->obj != NULL) {
+ cil_log(CIL_INFO, " %s", rangetrans->obj->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", rangetrans->obj_str);
+ }
+
+ if (rangetrans->range != NULL) {
+ cil_log(CIL_INFO, " (");
+ cil_tree_print_levelrange(rangetrans->range);
+ cil_log(CIL_INFO, " )");
+ } else {
+ cil_log(CIL_INFO, " %s", rangetrans->range_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_AVRULE: {
+ struct cil_avrule *rule = node->data;
+ switch (rule->rule_kind) {
+ case CIL_AVRULE_ALLOWED:
+ cil_log(CIL_INFO, "ALLOW:");
+ break;
+ case CIL_AVRULE_AUDITALLOW:
+ cil_log(CIL_INFO, "AUDITALLOW:");
+ break;
+ case CIL_AVRULE_DONTAUDIT:
+ cil_log(CIL_INFO, "DONTAUDIT:");
+ break;
+ case CIL_AVRULE_NEVERALLOW:
+ cil_log(CIL_INFO, "NEVERALLOW:");
+ break;
+ }
+
+ if (rule->src != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->src)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rule->src_str);
+ }
+
+ if (rule->tgt != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum*)rule->tgt)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rule->tgt_str);
+ }
+
+ cil_tree_print_classperms_list(rule->perms.classperms);
+
+ cil_log(CIL_INFO, "\n");
+
+ return;
+ }
+ case CIL_TYPE_RULE: {
+ struct cil_type_rule *rule = node->data;
+ switch (rule->rule_kind) {
+ case CIL_TYPE_TRANSITION:
+ cil_log(CIL_INFO, "TYPETRANSITION:");
+ break;
+ case CIL_TYPE_MEMBER:
+ cil_log(CIL_INFO, "TYPEMEMBER:");
+ break;
+ case CIL_TYPE_CHANGE:
+ cil_log(CIL_INFO, "TYPECHANGE:");
+ break;
+ }
+
+ if (rule->src != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->src)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rule->src_str);
+ }
+
+ if (rule->tgt != NULL) {
+ cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)rule->tgt)->name);
+ } else {
+ cil_log(CIL_INFO, " %s", rule->tgt_str);
+ }
+
+ if (rule->obj != NULL) {
+ cil_log(CIL_INFO, " %s", rule->obj->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", rule->obj_str);
+ }
+
+ if (rule->result != NULL) {
+ cil_log(CIL_INFO, " %s\n", ((struct cil_symtab_datum *)rule->result)->name);
+ } else {
+ cil_log(CIL_INFO, " %s\n", rule->result_str);
+ }
+
+ return;
+ }
+ case CIL_SENS: {
+ struct cil_sens *sens = node->data;
+ cil_log(CIL_INFO, "SENSITIVITY: %s\n", sens->datum.name);
+ return;
+ }
+ case CIL_SENSALIAS: {
+ struct cil_alias *alias = node->data;
+ cil_log(CIL_INFO, "SENSITIVITYALIAS: %s\n", alias->datum.name);
+ return;
+ }
+ case CIL_SENSALIASACTUAL: {
+ struct cil_aliasactual *aliasactual = node->data;
+ cil_log(CIL_INFO, "SENSITIVITYALIAS: alias: %s, sensitivity: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+
+ return;
+ }
+ case CIL_CAT: {
+ struct cil_cat *cat = node->data;
+ cil_log(CIL_INFO, "CATEGORY: %s\n", cat->datum.name);
+ return;
+ }
+ case CIL_CATALIAS: {
+ struct cil_alias *alias = node->data;
+ cil_log(CIL_INFO, "CATEGORYALIAS: %s\n", alias->datum.name);
+ return;
+ }
+ case CIL_CATALIASACTUAL: {
+ struct cil_aliasactual *aliasactual = node->data;
+ cil_log(CIL_INFO, "CATEGORYALIAS: alias %s, category: %s\n", aliasactual->alias_str, aliasactual->actual_str);
+ return;
+ }
+ case CIL_CATSET: {
+ struct cil_catset *catset = node->data;
+
+ cil_log(CIL_INFO, "CATSET: %s ",catset->datum.name);
+
+ cil_tree_print_cats(catset->cats);
+
+ return;
+ }
+ case CIL_CATORDER: {
+ struct cil_catorder *catorder = node->data;
+ struct cil_list_item *cat;
+
+ if (catorder->cat_list_str == NULL) {
+ cil_log(CIL_INFO, "CATORDER: ()\n");
+ return;
+ }
+
+ cil_log(CIL_INFO, "CATORDER: (");
+ cil_list_for_each(cat, catorder->cat_list_str) {
+ cil_log(CIL_INFO, " %s", (char*)cat->data);
+ }
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_SENSCAT: {
+ struct cil_senscat *senscat = node->data;
+
+ cil_log(CIL_INFO, "SENSCAT: sens:");
+
+ if (senscat->sens_str != NULL) {
+ cil_log(CIL_INFO, " %s ", senscat->sens_str);
+ } else {
+ cil_log(CIL_INFO, " [processed]");
+ }
+
+ cil_tree_print_cats(senscat->cats);
+
+ return;
+ }
+ case CIL_SENSITIVITYORDER: {
+ struct cil_sensorder *sensorder = node->data;
+ struct cil_list_item *sens;
+
+ cil_log(CIL_INFO, "SENSITIVITYORDER: (");
+
+ if (sensorder->sens_list_str != NULL) {
+ cil_list_for_each(sens, sensorder->sens_list_str) {
+ if (sens->flavor == CIL_LIST) {
+ struct cil_list_item *sub;
+ cil_log(CIL_INFO, " (");
+ cil_list_for_each(sub, (struct cil_list*)sens->data) {
+ cil_log(CIL_INFO, " %s", (char*)sub->data);
+ }
+ cil_log(CIL_INFO, " )");
+ } else {
+ cil_log(CIL_INFO, " %s", (char*)sens->data);
+ }
+ }
+ }
+
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_LEVEL: {
+ struct cil_level *level = node->data;
+ cil_log(CIL_INFO, "LEVEL %s:", level->datum.name);
+ cil_tree_print_level(level);
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_LEVELRANGE: {
+ struct cil_levelrange *lvlrange = node->data;
+ cil_log(CIL_INFO, "LEVELRANGE %s:", lvlrange->datum.name);
+ cil_tree_print_levelrange(lvlrange);
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_CONSTRAIN: {
+ struct cil_constrain *cons = node->data;
+ cil_log(CIL_INFO, "CONSTRAIN: (");
+ cil_tree_print_constrain(cons);
+ return;
+ }
+ case CIL_MLSCONSTRAIN: {
+ struct cil_constrain *cons = node->data;
+ cil_log(CIL_INFO, "MLSCONSTRAIN: (");
+ cil_tree_print_constrain(cons);
+ return;
+ }
+ case CIL_VALIDATETRANS: {
+ struct cil_validatetrans *vt = node->data;
+
+ cil_log(CIL_INFO, "(VALIDATETRANS ");
+
+ if (vt->class != NULL) {
+ cil_log(CIL_INFO, "%s ", vt->class->datum.name);
+ } else if (vt->class_str != NULL) {
+ cil_log(CIL_INFO, "%s ", vt->class_str);
+ }
+
+ cil_tree_print_expr(vt->datum_expr, vt->str_expr);
+
+ cil_log(CIL_INFO, ")\n");
+ return;
+ }
+ case CIL_MLSVALIDATETRANS: {
+ struct cil_validatetrans *vt = node->data;
+
+ cil_log(CIL_INFO, "(MLSVALIDATETRANS ");
+
+ if (vt->class != NULL) {
+ cil_log(CIL_INFO, "%s ", vt->class->datum.name);
+ } else if (vt->class_str != NULL) {
+ cil_log(CIL_INFO, "%s ", vt->class_str);
+ }
+
+ cil_tree_print_expr(vt->datum_expr, vt->str_expr);
+
+ cil_log(CIL_INFO, ")\n");
+ return;
+ }
+ case CIL_CONTEXT: {
+ struct cil_context *context = node->data;
+ cil_log(CIL_INFO, "CONTEXT %s:", context->datum.name);
+ cil_tree_print_context(context);
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_FILECON: {
+ struct cil_filecon *filecon = node->data;
+ cil_log(CIL_INFO, "FILECON:");
+ cil_log(CIL_INFO, " %s %d", filecon->path_str, filecon->type);
+
+ if (filecon->context != NULL) {
+ cil_tree_print_context(filecon->context);
+ } else if (filecon->context_str != NULL) {
+ cil_log(CIL_INFO, " %s", filecon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+
+ }
+ case CIL_PORTCON: {
+ struct cil_portcon *portcon = node->data;
+ cil_log(CIL_INFO, "PORTCON:");
+ if (portcon->proto == CIL_PROTOCOL_UDP) {
+ cil_log(CIL_INFO, " udp");
+ } else if (portcon->proto == CIL_PROTOCOL_TCP) {
+ cil_log(CIL_INFO, " tcp");
+ } else if (portcon->proto == CIL_PROTOCOL_DCCP) {
+ cil_log(CIL_INFO, " dccp");
+ }
+ cil_log(CIL_INFO, " (%d %d)", portcon->port_low, portcon->port_high);
+
+ if (portcon->context != NULL) {
+ cil_tree_print_context(portcon->context);
+ } else if (portcon->context_str != NULL) {
+ cil_log(CIL_INFO, " %s", portcon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_NODECON: {
+ struct cil_nodecon *nodecon = node->data;
+ char buf[256];
+
+ cil_log(CIL_INFO, "NODECON:");
+
+ if (nodecon->addr) {
+ inet_ntop(nodecon->addr->family, &nodecon->addr->ip, buf, 256);
+ cil_log(CIL_INFO, " %s", buf);
+ } else {
+ cil_log(CIL_INFO, " %s", nodecon->addr_str);
+ }
+
+ if (nodecon->mask) {
+ inet_ntop(nodecon->mask->family, &nodecon->mask->ip, buf, 256);
+ cil_log(CIL_INFO, " %s", buf);
+ } else {
+ cil_log(CIL_INFO, " %s", nodecon->mask_str);
+ }
+
+ if (nodecon->context != NULL) {
+ cil_tree_print_context(nodecon->context);
+ } else if (nodecon->context_str != NULL) {
+ cil_log(CIL_INFO, " %s", nodecon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_GENFSCON: {
+ struct cil_genfscon *genfscon = node->data;
+ cil_log(CIL_INFO, "GENFSCON:");
+ cil_log(CIL_INFO, " %s %s", genfscon->fs_str, genfscon->path_str);
+
+ if (genfscon->context != NULL) {
+ cil_tree_print_context(genfscon->context);
+ } else if (genfscon->context_str != NULL) {
+ cil_log(CIL_INFO, " %s", genfscon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_NETIFCON: {
+ struct cil_netifcon *netifcon = node->data;
+ cil_log(CIL_INFO, "NETIFCON %s", netifcon->interface_str);
+
+ if (netifcon->if_context != NULL) {
+ cil_tree_print_context(netifcon->if_context);
+ } else if (netifcon->if_context_str != NULL) {
+ cil_log(CIL_INFO, " %s", netifcon->if_context_str);
+ }
+
+ if (netifcon->packet_context != NULL) {
+ cil_tree_print_context(netifcon->packet_context);
+ } else if (netifcon->packet_context_str != NULL) {
+ cil_log(CIL_INFO, " %s", netifcon->packet_context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_PIRQCON: {
+ struct cil_pirqcon *pirqcon = node->data;
+
+ cil_log(CIL_INFO, "PIRQCON %d", pirqcon->pirq);
+ if (pirqcon->context != NULL) {
+ cil_tree_print_context(pirqcon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", pirqcon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_IOMEMCON: {
+ struct cil_iomemcon *iomemcon = node->data;
+
+ cil_log(CIL_INFO, "IOMEMCON ( %"PRId64" %"PRId64" )", iomemcon->iomem_low, iomemcon->iomem_high);
+ if (iomemcon->context != NULL) {
+ cil_tree_print_context(iomemcon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", iomemcon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_IOPORTCON: {
+ struct cil_ioportcon *ioportcon = node->data;
+
+ cil_log(CIL_INFO, "IOPORTCON ( %d %d )", ioportcon->ioport_low, ioportcon->ioport_high);
+ if (ioportcon->context != NULL) {
+ cil_tree_print_context(ioportcon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", ioportcon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_PCIDEVICECON: {
+ struct cil_pcidevicecon *pcidevicecon = node->data;
+
+ cil_log(CIL_INFO, "PCIDEVICECON %d", pcidevicecon->dev);
+ if (pcidevicecon->context != NULL) {
+ cil_tree_print_context(pcidevicecon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", pcidevicecon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_DEVICETREECON: {
+ struct cil_devicetreecon *devicetreecon = node->data;
+
+ cil_log(CIL_INFO, "DEVICETREECON %s", devicetreecon->path);
+ if (devicetreecon->context != NULL) {
+ cil_tree_print_context(devicetreecon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", devicetreecon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_FSUSE: {
+ struct cil_fsuse *fsuse = node->data;
+ cil_log(CIL_INFO, "FSUSE: ");
+
+ if (fsuse->type == CIL_FSUSE_XATTR) {
+ cil_log(CIL_INFO, "xattr ");
+ } else if (fsuse->type == CIL_FSUSE_TASK) {
+ cil_log(CIL_INFO, "task ");
+ } else if (fsuse->type == CIL_FSUSE_TRANS) {
+ cil_log(CIL_INFO, "trans ");
+ } else {
+ cil_log(CIL_INFO, "unknown ");
+ }
+
+ cil_log(CIL_INFO, "%s ", fsuse->fs_str);
+
+ if (fsuse->context != NULL) {
+ cil_tree_print_context(fsuse->context);
+ } else {
+ cil_log(CIL_INFO, " %s", fsuse->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_SID: {
+ struct cil_sid *sid = node->data;
+ cil_log(CIL_INFO, "SID: %s\n", sid->datum.name);
+ return;
+ }
+ case CIL_SIDCONTEXT: {
+ struct cil_sidcontext *sidcon = node->data;
+ cil_log(CIL_INFO, "SIDCONTEXT: %s", sidcon->sid_str);
+
+ if (sidcon->context != NULL) {
+ cil_tree_print_context(sidcon->context);
+ } else {
+ cil_log(CIL_INFO, " %s", sidcon->context_str);
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_SIDORDER: {
+ struct cil_sidorder *sidorder = node->data;
+ struct cil_list_item *sid;
+
+ if (sidorder->sid_list_str == NULL) {
+ cil_log(CIL_INFO, "SIDORDER: ()\n");
+ return;
+ }
+
+ cil_log(CIL_INFO, "SIDORDER: (");
+ cil_list_for_each(sid, sidorder->sid_list_str) {
+ cil_log(CIL_INFO, " %s", (char*)sid->data);
+ }
+ cil_log(CIL_INFO, " )\n");
+ return;
+ }
+ case CIL_POLICYCAP: {
+ struct cil_policycap *polcap = node->data;
+ cil_log(CIL_INFO, "POLICYCAP: %s\n", polcap->datum.name);
+ return;
+ }
+ case CIL_MACRO: {
+ struct cil_macro *macro = node->data;
+ cil_log(CIL_INFO, "MACRO %s:", macro->datum.name);
+
+ if (macro->params != NULL && macro->params->head != NULL) {
+ struct cil_list_item *curr_param;
+ cil_log(CIL_INFO, " parameters: (");
+ cil_list_for_each(curr_param, macro->params) {
+ cil_log(CIL_INFO, " flavor: %d, string: %s;", ((struct cil_param*)curr_param->data)->flavor, ((struct cil_param*)curr_param->data)->str);
+
+ }
+ cil_log(CIL_INFO, " )");
+ }
+ cil_log(CIL_INFO, "\n");
+
+ return;
+ }
+ case CIL_CALL: {
+ struct cil_call *call = node->data;
+ cil_log(CIL_INFO, "CALL: macro name:");
+
+ if (call->macro != NULL) {
+ cil_log(CIL_INFO, " %s", call->macro->datum.name);
+ } else {
+ cil_log(CIL_INFO, " %s", call->macro_str);
+ }
+
+ if (call->args != NULL) {
+ cil_log(CIL_INFO, ", args: ( ");
+ struct cil_list_item *item;
+ cil_list_for_each(item, call->args) {
+ struct cil_symtab_datum *datum = ((struct cil_args*)item->data)->arg;
+ if (datum != NULL) {
+ if (datum->nodes != NULL && datum->nodes->head != NULL) {
+ cil_tree_print_node((struct cil_tree_node*)datum->nodes->head->data);
+ }
+ } else if (((struct cil_args*)item->data)->arg_str != NULL) {
+ switch (item->flavor) {
+ case CIL_TYPE: cil_log(CIL_INFO, "type:"); break;
+ case CIL_USER: cil_log(CIL_INFO, "user:"); break;
+ case CIL_ROLE: cil_log(CIL_INFO, "role:"); break;
+ case CIL_SENS: cil_log(CIL_INFO, "sensitivity:"); break;
+ case CIL_CAT: cil_log(CIL_INFO, "category:"); break;
+ case CIL_CATSET: cil_log(CIL_INFO, "categoryset:"); break;
+ case CIL_LEVEL: cil_log(CIL_INFO, "level:"); break;
+ case CIL_CLASS: cil_log(CIL_INFO, "class:"); break;
+ default: break;
+ }
+ cil_log(CIL_INFO, "%s ", ((struct cil_args*)item->data)->arg_str);
+ }
+ }
+ cil_log(CIL_INFO, ")");
+ }
+
+ cil_log(CIL_INFO, "\n");
+ return;
+ }
+ case CIL_OPTIONAL: {
+ struct cil_optional *optional = node->data;
+ cil_log(CIL_INFO, "OPTIONAL: %s\n", optional->datum.name);
+ return;
+ }
+ case CIL_IPADDR: {
+ struct cil_ipaddr *ipaddr = node->data;
+ char buf[256];
+
+ inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256);
+ cil_log(CIL_INFO, "IPADDR %s: %s\n", ipaddr->datum.name, buf);
+
+ break;
+ }
+ default : {
+ cil_log(CIL_INFO, "CIL FLAVOR: %d\n", node->flavor);
+ return;
+ }
+ }
+ }
+}
+
+void cil_tree_print(struct cil_tree_node *tree, uint32_t depth)
+{
+ struct cil_tree_node *current = NULL;
+ current = tree;
+ uint32_t x = 0;
+
+ if (current != NULL) {
+ if (current->cl_head == NULL) {
+ if (current->flavor == CIL_NODE) {
+ if (current->parent->cl_head == current) {
+ cil_log(CIL_INFO, "%s", (char*)current->data);
+ } else {
+ cil_log(CIL_INFO, " %s", (char*)current->data);
+ }
+ } else if (current->flavor != CIL_PERM) {
+ for (x = 0; x<depth; x++) {
+ cil_log(CIL_INFO, "\t");
+ }
+ cil_tree_print_node(current);
+ }
+ } else {
+ if (current->parent != NULL) {
+ cil_log(CIL_INFO, "\n");
+ for (x = 0; x<depth; x++) {
+ cil_log(CIL_INFO, "\t");
+ }
+ cil_log(CIL_INFO, "(");
+
+ if (current->flavor != CIL_NODE) {
+ cil_tree_print_node(current);
+ }
+ }
+ cil_tree_print(current->cl_head, depth + 1);
+ }
+
+ if (current->next == NULL) {
+ if ((current->parent != NULL) && (current->parent->cl_tail == current) && (current->parent->parent != NULL)) {
+ if (current->flavor == CIL_PERM) {
+ cil_log(CIL_INFO, ")\n");
+ } else if (current->flavor != CIL_NODE) {
+ for (x = 0; x<depth-1; x++) {
+ cil_log(CIL_INFO, "\t");
+ }
+ cil_log(CIL_INFO, ")\n");
+ } else {
+ cil_log(CIL_INFO, ")");
+ }
+ }
+
+ if ((current->parent != NULL) && (current->parent->parent == NULL))
+ cil_log(CIL_INFO, "\n\n");
+ } else {
+ cil_tree_print(current->next, depth);
+ }
+ } else {
+ cil_log(CIL_INFO, "Tree is NULL\n");
+ }
+}
diff --git a/libsepol/cil/src/cil_tree.h b/libsepol/cil/src/cil_tree.h
new file mode 100644
index 0000000..aeded56
--- /dev/null
+++ b/libsepol/cil/src/cil_tree.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_TREE_H_
+#define CIL_TREE_H_
+
+#include <stdint.h>
+
+#include "cil_flavor.h"
+#include "cil_list.h"
+
+struct cil_tree {
+ struct cil_tree_node *root;
+};
+
+struct cil_tree_node {
+ struct cil_tree_node *parent;
+ struct cil_tree_node *cl_head; //Head of child_list
+ struct cil_tree_node *cl_tail; //Tail of child_list
+ struct cil_tree_node *next; //Each element in the list points to the next element
+ enum cil_flavor flavor;
+ uint32_t line;
+ uint32_t hll_line;
+ void *data;
+};
+
+struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil);
+char *cil_tree_get_cil_path(struct cil_tree_node *node);
+__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...);
+
+int cil_tree_init(struct cil_tree **tree);
+void cil_tree_destroy(struct cil_tree **tree);
+void cil_tree_subtree_destroy(struct cil_tree_node *node);
+void cil_tree_children_destroy(struct cil_tree_node *node);
+
+void cil_tree_node_init(struct cil_tree_node **node);
+void cil_tree_node_destroy(struct cil_tree_node **node);
+
+void cil_tree_print(struct cil_tree_node *tree, uint32_t depth);
+
+//finished values
+#define CIL_TREE_SKIP_NOTHING 0
+#define CIL_TREE_SKIP_NEXT 1
+#define CIL_TREE_SKIP_HEAD 2
+#define CIL_TREE_SKIP_ALL (CIL_TREE_SKIP_NOTHING | CIL_TREE_SKIP_NEXT | CIL_TREE_SKIP_HEAD)
+int cil_tree_walk(struct cil_tree_node *start_node, int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), int (*first_child)(struct cil_tree_node *node, void *extra_args), int (*last_child)(struct cil_tree_node *node, void *extra_args), void *extra_args);
+
+#endif /* CIL_TREE_H_ */
+
diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c
new file mode 100644
index 0000000..038f77a
--- /dev/null
+++ b/libsepol/cil/src/cil_verify.c
@@ -0,0 +1,1644 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <sepol/policydb/polcaps.h>
+#include <sepol/errcodes.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_log.h"
+#include "cil_mem.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+#include "cil_find.h"
+
+#include "cil_verify.h"
+
+int __cil_verify_name(const char *name)
+{
+ int rc = SEPOL_ERR;
+ int len = strlen(name);
+ int i = 0;
+
+ if (len >= CIL_MAX_NAME_LENGTH) {
+ cil_log(CIL_ERR, "Name length greater than max name length of %d",
+ CIL_MAX_NAME_LENGTH);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (!isalpha(name[0])) {
+ cil_log(CIL_ERR, "First character in %s is not a letter\n", name);
+ goto exit;
+ }
+
+ for (i = 1; i < len; i++) {
+ if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') {
+ cil_log(CIL_ERR, "Invalid character \"%c\" in %s\n", name[i], name);
+ goto exit;
+ }
+ }
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Invalid name\n");
+ return rc;
+}
+
+int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len)
+{
+ int rc = SEPOL_ERR;
+ int num_extras = 0;
+ struct cil_tree_node *c = parse_current;
+ int i = 0;
+ while (i < len) {
+ if ((s[i] & CIL_SYN_END) && c == NULL) {
+ break;
+ }
+
+ if (s[i] & CIL_SYN_N_LISTS || s[i] & CIL_SYN_N_STRINGS) {
+ if (c == NULL) {
+ if (num_extras > 0) {
+ i++;
+ continue;
+ } else {
+ goto exit;
+ }
+ } else if ((s[i] & CIL_SYN_N_LISTS) && (c->data == NULL && c->cl_head != NULL)) {
+ c = c->next;
+ num_extras++;
+ continue;
+ } else if ((s[i] & CIL_SYN_N_STRINGS) && (c->data != NULL && c->cl_head == NULL)) {
+ c = c->next;
+ num_extras++;
+ continue;
+ }
+ }
+
+ if (c == NULL) {
+ goto exit;
+ }
+
+ if (s[i] & CIL_SYN_STRING) {
+ if (c->data != NULL && c->cl_head == NULL) {
+ c = c->next;
+ i++;
+ continue;
+ }
+ }
+
+ if (s[i] & CIL_SYN_LIST) {
+ if (c->data == NULL && c->cl_head != NULL) {
+ c = c->next;
+ i++;
+ continue;
+ }
+ }
+
+ if (s[i] & CIL_SYN_EMPTY_LIST) {
+ if (c->data == NULL && c->cl_head == NULL) {
+ c = c->next;
+ i++;
+ continue;
+ }
+ }
+ goto exit;
+ }
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Invalid syntax\n");
+ return rc;
+}
+
+int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor)
+{
+ int rc;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ switch (op) {
+ case CIL_NOT:
+ syntax[2] = CIL_SYN_END;
+ syntax_len = 3;
+ break;
+ case CIL_AND:
+ case CIL_OR:
+ case CIL_XOR:
+ break;
+ case CIL_EQ:
+ case CIL_NEQ:
+ if (expr_flavor != CIL_BOOL && expr_flavor != CIL_TUNABLE ) {
+ cil_log(CIL_ERR,"Invalid operator (%s) for set expression\n", (char*)current->data);
+ goto exit;
+ }
+ break;
+ case CIL_ALL:
+ if (expr_flavor == CIL_BOOL || expr_flavor == CIL_TUNABLE) {
+ cil_log(CIL_ERR,"Invalid operator (%s) for boolean or tunable expression\n", (char*)current->data);
+ goto exit;
+ }
+ syntax[1] = CIL_SYN_END;
+ syntax_len = 2;
+ break;
+ case CIL_RANGE:
+ if (expr_flavor != CIL_CAT && expr_flavor != CIL_PERMISSIONX) {
+ cil_log(CIL_ERR,"Operator (%s) only valid for catset and permissionx expression\n", (char*)current->data);
+ goto exit;
+ }
+ syntax[1] = CIL_SYN_STRING;
+ syntax[2] = CIL_SYN_STRING;
+ break;
+ case CIL_NONE: /* String or List */
+ syntax[0] = CIL_SYN_N_STRINGS | CIL_SYN_N_LISTS;
+ syntax[1] = CIL_SYN_END;
+ syntax_len = 2;
+ break;
+ default:
+ cil_log(CIL_ERR,"Unexpected value (%s) for expression operator\n", (char*)current->data);
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor)
+{
+ if (r_flavor == CIL_STRING || r_flavor == CIL_LIST) {
+ if (l_flavor == CIL_CONS_L1 || l_flavor == CIL_CONS_L2 || l_flavor == CIL_CONS_H1 || l_flavor == CIL_CONS_H2 ) {
+ cil_log(CIL_ERR, "l1, l2, h1, and h2 cannot be used on the left side with a string or list on the right side\n");
+ goto exit;
+ } else if (l_flavor == CIL_CONS_U3 || l_flavor == CIL_CONS_R3 || l_flavor == CIL_CONS_T3) {
+ if (expr_flavor != CIL_MLSVALIDATETRANS) {
+ cil_log(CIL_ERR, "u3, r3, and t3 can only be used with mlsvalidatetrans rules\n");
+ goto exit;
+ }
+ }
+ } else {
+ if (r_flavor == CIL_CONS_U2) {
+ if (op != CIL_EQ && op != CIL_NEQ) {
+ cil_log(CIL_ERR, "u2 on the right side must be used with eq or neq as the operator\n");
+ goto exit;
+ } else if (l_flavor != CIL_CONS_U1) {
+ cil_log(CIL_ERR, "u2 on the right side must be used with u1 on the left\n");
+ goto exit;
+ }
+ } else if (r_flavor == CIL_CONS_R2) {
+ if (l_flavor != CIL_CONS_R1) {
+ cil_log(CIL_ERR, "r2 on the right side must be used with r1 on the left\n");
+ goto exit;
+ }
+ } else if (r_flavor == CIL_CONS_T2) {
+ if (op != CIL_EQ && op != CIL_NEQ) {
+ cil_log(CIL_ERR, "t2 on the right side must be used with eq or neq as the operator\n");
+ goto exit;
+ } else if (l_flavor != CIL_CONS_T1) {
+ cil_log(CIL_ERR, "t2 on the right side must be used with t1 on the left\n");
+ goto exit;
+ }
+ } else if (r_flavor == CIL_CONS_L2) {
+ if (l_flavor != CIL_CONS_L1 && l_flavor != CIL_CONS_H1) {
+ cil_log(CIL_ERR, "l2 on the right side must be used with l1 or h1 on the left\n");
+ goto exit;
+ }
+ } else if (r_flavor == CIL_CONS_H2) {
+ if (l_flavor != CIL_CONS_L1 && l_flavor != CIL_CONS_L2 && l_flavor != CIL_CONS_H1 ) {
+ cil_log(CIL_ERR, "h2 on the right side must be used with l1, l2, or h1 on the left\n");
+ goto exit;
+ }
+ } else if (r_flavor == CIL_CONS_H1) {
+ if (l_flavor != CIL_CONS_L1) {
+ cil_log(CIL_ERR, "h1 on the right side must be used with l1 on the left\n");
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op)
+{
+ int rc;
+ enum cil_syntax syntax[] = {
+ CIL_SYN_STRING,
+ CIL_SYN_END,
+ CIL_SYN_END,
+ CIL_SYN_END
+ };
+ int syntax_len = sizeof(syntax)/sizeof(*syntax);
+
+ switch (op) {
+ case CIL_NOT:
+ syntax[1] = CIL_SYN_LIST;
+ syntax_len--;
+ break;
+ case CIL_AND:
+ case CIL_OR:
+ syntax[1] = CIL_SYN_LIST;
+ syntax[2] = CIL_SYN_LIST;
+ break;
+ case CIL_EQ:
+ case CIL_NEQ:
+ syntax[1] = CIL_SYN_STRING;
+ syntax[2] = CIL_SYN_STRING | CIL_SYN_LIST;
+ break;
+ case CIL_CONS_DOM:
+ case CIL_CONS_DOMBY:
+ case CIL_CONS_INCOMP:
+ syntax[1] = CIL_SYN_STRING;
+ syntax[2] = CIL_SYN_STRING;
+ break;
+ default:
+ cil_log(CIL_ERR, "Invalid operator (%s) for constraint expression\n", (char*)current->data);
+ goto exit;
+ }
+
+ rc = __cil_verify_syntax(current, syntax, syntax_len);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Invalid constraint syntax\n");
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list)
+{
+ struct cil_list_item *i;
+
+ cil_list_for_each(i, datum_list) {
+ if (i->flavor == CIL_DATUM) {
+ struct cil_symtab_datum *d = i->data;
+ if (d == datum) {
+ cil_log(CIL_ERR,"Self-reference found for %s\n",datum->name);
+ return SEPOL_ERR;
+ }
+ } else if (i->flavor == CIL_LIST) {
+ int rc = cil_verify_no_self_reference(datum, i->data);
+ if (rc != SEPOL_OK) {
+ return SEPOL_ERR;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_verify_ranges(struct cil_list *list)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+ struct cil_list_item *range = NULL;
+
+ if (list == NULL || list->head == NULL) {
+ goto exit;
+ }
+
+ cil_list_for_each(curr, list) {
+ /* range */
+ if (curr->flavor == CIL_LIST) {
+ range = ((struct cil_list*)curr->data)->head;
+ if (range == NULL || range->next == NULL || range->next->next != NULL) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR,"Invalid Range syntax\n");
+ return rc;
+}
+
+struct cil_args_verify_order {
+ uint32_t *flavor;
+};
+
+int __cil_verify_ordered_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
+{
+ struct cil_args_verify_order *args = extra_args;
+ uint32_t *flavor = args->flavor;
+
+ if (node->flavor == *flavor) {
+ if (node->flavor == CIL_SID) {
+ struct cil_sid *sid = node->data;
+ if (sid->ordered == CIL_FALSE) {
+ cil_tree_log(node, CIL_ERR, "SID %s not in sidorder statement", sid->datum.name);
+ return SEPOL_ERR;
+ }
+ } else if (node->flavor == CIL_CLASS) {
+ struct cil_class *class = node->data;
+ if (class->ordered == CIL_FALSE) {
+ cil_tree_log(node, CIL_ERR, "Class %s not in classorder statement", class->datum.name);
+ return SEPOL_ERR;
+ }
+ } else if (node->flavor == CIL_CAT) {
+ struct cil_cat *cat = node->data;
+ if (cat->ordered == CIL_FALSE) {
+ cil_tree_log(node, CIL_ERR, "Category %s not in categoryorder statement", cat->datum.name);
+ return SEPOL_ERR;
+ }
+ } else if (node->flavor == CIL_SENS) {
+ struct cil_sens *sens = node->data;
+ if (sens->ordered == CIL_FALSE) {
+ cil_tree_log(node, CIL_ERR, "Sensitivity %s not in sensitivityorder statement", sens->datum.name);
+ return SEPOL_ERR;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor)
+{
+ struct cil_args_verify_order extra_args;
+ int rc = SEPOL_ERR;
+
+ extra_args.flavor = &flavor;
+
+ rc = cil_tree_walk(current, __cil_verify_ordered_node_helper, NULL, NULL, &extra_args);
+
+ return rc;
+}
+
+int __cil_verify_initsids(struct cil_list *sids)
+{
+ int rc = SEPOL_OK;
+ struct cil_list_item *i;
+
+ if (sids->head == NULL) {
+ cil_log(CIL_ERR, "At least one initial sid must be defined in the policy\n");
+ return SEPOL_ERR;
+ }
+
+ cil_list_for_each(i, sids) {
+ struct cil_sid *sid = i->data;
+ if (sid->context == NULL) {
+ struct cil_tree_node *node = sid->datum.nodes->head->data;
+ cil_tree_log(node, CIL_ERR, "No context assigned to SID %s declared",sid->datum.name);
+ rc = SEPOL_ERR;
+ }
+ }
+
+ return rc;
+}
+
+int __cil_is_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats)
+{
+ struct cil_list_item *i;
+
+ cil_list_for_each(i, cats->datum_expr) {
+ struct cil_cat *c = i->data;
+ if (c == cat) {
+ return CIL_TRUE;
+ }
+ }
+
+ return CIL_FALSE;
+}
+
+
+int __cil_verify_cat_in_cats(struct cil_cat *cat, struct cil_cats *cats)
+{
+ if (__cil_is_cat_in_cats(cat, cats) != CIL_TRUE) {
+ cil_log(CIL_ERR, "Failed to find category %s in category list\n", cat->datum.name);
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_verify_cats_associated_with_sens(struct cil_sens *sens, struct cil_cats *cats)
+{
+ int rc = SEPOL_OK;
+ struct cil_list_item *i, *j;
+
+ if (!cats) {
+ return SEPOL_OK;
+ }
+
+ if (!sens->cats_list) {
+ cil_log(CIL_ERR, "No categories can be used with sensitivity %s\n", sens->datum.name);
+ return SEPOL_ERR;
+ }
+
+ cil_list_for_each(i, cats->datum_expr) {
+ struct cil_cat *cat = i->data;
+ int ok = CIL_FALSE;
+ cil_list_for_each(j, sens->cats_list) {
+ if (__cil_is_cat_in_cats(cat, j->data) == CIL_TRUE) {
+ ok = CIL_TRUE;
+ break;
+ }
+ }
+
+ if (ok != CIL_TRUE) {
+ cil_log(CIL_ERR, "Category %s cannot be used with sensitivity %s\n",
+ cat->datum.name, sens->datum.name);
+ rc = SEPOL_ERR;
+ }
+ }
+
+ return rc;
+}
+
+int __cil_verify_levelrange_sensitivity(struct cil_db *db, struct cil_sens *low, struct cil_sens *high)
+{
+ struct cil_list_item *curr;
+ int found = CIL_FALSE;
+ int rc = SEPOL_ERR;
+
+ cil_list_for_each(curr, db->sensitivityorder) {
+ if (curr->data == low) {
+ found = CIL_TRUE;
+ }
+
+ if ((found == CIL_TRUE) && (curr->data == high)) {
+ break;
+ }
+ }
+
+ if (found != CIL_TRUE || curr == NULL) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Sensitivity %s does not dominate %s\n",
+ high->datum.name, low->datum.name);
+ return rc;
+
+}
+
+int __cil_verify_levelrange_cats(struct cil_cats *low, struct cil_cats *high)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *item;
+
+ if (low == NULL || (low == NULL && high == NULL)) {
+ return SEPOL_OK;
+ }
+
+ if (high == NULL) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ cil_list_for_each(item, low->datum_expr) {
+ rc = __cil_verify_cat_in_cats(item->data, high);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_log(CIL_ERR, "Low level category set must be a subset of the high level category set\n");
+ return rc;
+}
+
+int __cil_verify_levelrange(struct cil_db *db, struct cil_levelrange *lr)
+{
+ int rc = SEPOL_ERR;
+
+ rc = __cil_verify_levelrange_sensitivity(db, lr->low->sens, lr->high->sens);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_verify_levelrange_cats(lr->low->cats, lr->high->cats);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ rc = __cil_verify_cats_associated_with_sens(lr->low->sens, lr->low->cats);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "Low level sensitivity and categories are not associated\n");
+ goto exit;
+ }
+
+ rc = __cil_verify_cats_associated_with_sens(lr->high->sens, lr->high->cats);
+ if (rc != SEPOL_OK) {
+ cil_log(CIL_ERR, "High level sensitivity and categories are not associated\n");
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_verify_named_levelrange(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_levelrange *lr = node->data;
+
+ rc = __cil_verify_levelrange(db, lr);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid named range");
+ return rc;
+}
+
+static int __cil_verify_user_pre_eval(struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_user *user = node->data;
+
+ if (user->dftlevel == NULL) {
+ cil_log(CIL_ERR, "User %s does not have a default level\n", user->datum.name);
+ goto exit;
+ } else if (user->range == NULL) {
+ cil_log(CIL_ERR, "User %s does not have a level range\n", user->datum.name);
+ goto exit;
+ } else if (user->bounds != NULL) {
+ int steps = 0;
+ int limit = 2;
+ struct cil_user *u1 = user;
+ struct cil_user *u2 = user->bounds;
+
+ while (u2 != NULL) {
+ if (u1 == u2) {
+ cil_log(CIL_ERR, "Circular bounds found for user %s\n", u1->datum.name);
+ goto exit;
+ }
+
+ if (steps == limit) {
+ steps = 0;
+ limit *= 2;
+ u1 = u2;
+ }
+
+ u2 = u2->bounds;
+ steps++;
+ }
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid user");
+ return rc;
+}
+
+static int __cil_verify_user_post_eval(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_user *user = node->data;
+
+ /* Verify user range only if anonymous */
+ if (user->range->datum.name == NULL) {
+ rc = __cil_verify_levelrange(db, user->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid user");
+ return rc;
+}
+
+int __cil_verify_role(struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_role *role = node->data;
+ int steps = 0;
+ int limit = 2;
+ struct cil_role *r1 = role;
+ struct cil_role *r2 = role->bounds;
+
+ while (r2 != NULL) {
+ if (r1 == r2) {
+ cil_log(CIL_ERR, "Circular bounds found for role %s\n", r1->datum.name);
+ goto exit;
+ }
+
+ if (steps == limit) {
+ steps = 0;
+ limit *= 2;
+ r1 = r2;
+ }
+
+ r2 = r2->bounds;
+ steps++;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid role");
+ return rc;
+}
+
+int __cil_verify_type(struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_type *type = node->data;
+ int steps = 0;
+ int limit = 2;
+ struct cil_type *t1 = type;
+ struct cil_type *t2 = type->bounds;
+
+ while (t2 != NULL) {
+ if (t1 == t2) {
+ cil_log(CIL_ERR, "Circular bounds found for type %s\n", t1->datum.name);
+ goto exit;
+ }
+
+ if (steps == limit) {
+ steps = 0;
+ limit *= 2;
+ t1 = t2;
+ }
+
+ t2 = t2->bounds;
+ steps++;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid type");
+ return rc;
+}
+
+int __cil_verify_context(struct cil_db *db, struct cil_context *ctx)
+{
+ int rc = SEPOL_ERR;
+ struct cil_user *user = ctx->user;
+ struct cil_role *role = ctx->role;
+ struct cil_type *type = ctx->type;
+ struct cil_level *user_low = user->range->low;
+ struct cil_level *user_high = user->range->high;
+ struct cil_level *ctx_low = ctx->range->low;
+ struct cil_level *ctx_high = ctx->range->high;
+ struct cil_list *sensitivityorder = db->sensitivityorder;
+ struct cil_list_item *curr;
+ int found = CIL_FALSE;
+
+ if (user->roles != NULL) {
+ if (!ebitmap_get_bit(user->roles, role->value)) {
+ cil_log(CIL_ERR, "Role %s is invalid for user %s\n", ctx->role_str, ctx->user_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR, "No roles given to the user %s\n", ctx->user_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ if (role->types != NULL) {
+ if (!ebitmap_get_bit(role->types, type->value)) {
+ cil_log(CIL_ERR, "Type %s is invalid for role %s\n", ctx->type_str, ctx->role_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ } else {
+ cil_log(CIL_ERR, "No types associated with role %s\n", ctx->role_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ /* Verify range only when anonymous */
+ if (ctx->range->datum.name == NULL) {
+ rc = __cil_verify_levelrange(db, ctx->range);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ for (curr = sensitivityorder->head; curr != NULL; curr = curr->next) {
+ struct cil_sens *sens = curr->data;
+
+ if (found == CIL_FALSE) {
+ if (sens == user_low->sens) {
+ found = CIL_TRUE;
+ } else if (sens == ctx_low->sens) {
+ cil_log(CIL_ERR, "Range %s is invalid for user %s\n",
+ ctx->range_str, ctx->user_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ if (found == CIL_TRUE) {
+ if (sens == ctx_high->sens) {
+ break;
+ } else if (sens == user_high->sens) {
+ cil_log(CIL_ERR, "Range %s is invalid for user %s\n",
+ ctx->range_str, ctx->user_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_log(CIL_ERR, "Invalid context\n");
+ return rc;
+}
+
+int __cil_verify_named_context(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_context *ctx = node->data;
+
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid named context");
+ return rc;
+}
+
+int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *symtab)
+{
+
+ int rc = SEPOL_ERR;
+ struct cil_type_rule *typerule = NULL;
+ struct cil_roletransition *roletrans = NULL;
+ struct cil_complex_symtab_key ckey;
+
+ switch (node->flavor) {
+ case CIL_ROLETRANSITION: {
+ roletrans = node->data;
+ ckey.key1 = (intptr_t)roletrans->src;
+ ckey.key2 = (intptr_t)roletrans->tgt;
+ ckey.key3 = (intptr_t)roletrans->obj;
+ ckey.key4 = CIL_ROLETRANSITION;
+ break;
+ }
+ case CIL_TYPE_RULE: {
+ typerule = node->data;
+ ckey.key1 = (intptr_t)typerule->src;
+ ckey.key2 = (intptr_t)typerule->tgt;
+ ckey.key3 = (intptr_t)typerule->obj;
+ ckey.key4 = (intptr_t)typerule->rule_kind;
+ break;
+ }
+ default:
+ break;
+ }
+
+
+ rc = cil_complex_symtab_insert(symtab, &ckey, NULL);
+ if (rc == SEPOL_EEXIST) {
+ struct cil_complex_symtab_datum *datum = NULL;
+ cil_complex_symtab_search(symtab, &ckey, &datum);
+ if (datum == NULL) {
+ cil_tree_log(node, CIL_ERR, "Duplicate rule defined");
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid rule");
+ return rc;
+}
+
+int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_tree_node *rule_node = node;
+ struct cil_booleanif *bif = node->parent->parent->data;
+
+ switch (rule_node->flavor) {
+ case CIL_AVRULE: {
+ struct cil_avrule *avrule = NULL;
+ avrule = rule_node->data;
+ if (avrule->rule_kind == CIL_AVRULE_NEVERALLOW) {
+ if (bif->preserved_tunable) {
+ cil_tree_log(node, CIL_ERR, "Neverallow found in tunableif block (treated as a booleanif due to preserve-tunables)");
+ } else {
+ cil_tree_log(node, CIL_ERR, "Neverallow found in booleanif block");
+ }
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ break;
+ }
+ case CIL_TYPE_RULE: /*
+ struct cil_type_rule *typerule = NULL;
+ struct cil_tree_node *temp_node = NULL;
+ struct cil_complex_symtab *symtab = extra_args;
+ struct cil_complex_symtab_key ckey;
+ struct cil_complex_symtab_datum datum;
+ typerule = rule_node->data;
+
+ ckey.key1 = (intptr_t)typerule->src;
+ ckey.key2 = (intptr_t)typerule->tgt;
+ ckey.key3 = (intptr_t)typerule->obj;
+ ckey.key4 = (intptr_t)typerule->rule_kind;
+
+ datum.data = node;
+
+ rc = cil_complex_symtab_insert(symtab, &ckey, &datum);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+
+ for (temp_node = rule_node->next;
+ temp_node != NULL;
+ temp_node = temp_node->next) {
+
+ if (temp_node->flavor == CIL_TYPE_RULE) {
+ typerule = temp_node->data;
+ if ((intptr_t)typerule->src == ckey.key1 &&
+ (intptr_t)typerule->tgt == ckey.key2 &&
+ (intptr_t)typerule->obj == ckey.key3 &&
+ (intptr_t)typerule->rule_kind == ckey.key4) {
+ cil_log(CIL_ERR, "Duplicate type rule found (line: %d)\n", node->line);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+ break;*/
+
+ //TODO Fix duplicate type_rule detection
+ break;
+ case CIL_CALL:
+ //Fall through to check content of call
+ break;
+ case CIL_TUNABLEIF:
+ //Fall through
+ break;
+ case CIL_NAMETYPETRANSITION:
+ /* While type transitions with file component are not allowed in
+ booleanif statements if they don't have "*" as the file. We
+ can't check that here. Or at least we won't right now. */
+ break;
+ default: {
+ const char * flavor = cil_node_to_string(node);
+ if (bif->preserved_tunable) {
+ cil_tree_log(node, CIL_ERR, "Invalid %s statement in tunableif (treated as a booleanif due to preserve-tunables)", flavor);
+ } else {
+ cil_tree_log(node, CIL_ERR, "Invalid %s statement in booleanif", flavor);
+ }
+ goto exit;
+ }
+ }
+
+ rc = SEPOL_OK;
+exit:
+ return rc;
+}
+
+int __cil_verify_booleanif(struct cil_tree_node *node, struct cil_complex_symtab *symtab)
+{
+ int rc = SEPOL_ERR;
+ struct cil_booleanif *bif = (struct cil_booleanif*)node->data;
+ struct cil_tree_node *cond_block = node->cl_head;
+
+ while (cond_block != NULL) {
+ rc = cil_tree_walk(cond_block, __cil_verify_booleanif_helper, NULL, NULL, symtab);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ cond_block = cond_block->next;
+ }
+
+ return SEPOL_OK;
+exit:
+ if (bif->preserved_tunable) {
+ cil_tree_log(node, CIL_ERR, "Invalid tunableif (treated as a booleanif due to preserve-tunables)");
+ } else {
+ cil_tree_log(node, CIL_ERR, "Invalid booleanif");
+ }
+ return rc;
+}
+
+int __cil_verify_netifcon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_netifcon *netif = node->data;
+ struct cil_context *if_ctx = netif->if_context;
+ struct cil_context *pkt_ctx = netif->packet_context;
+
+ /* Verify only when anonymous */
+ if (if_ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, if_ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ /* Verify only when anonymous */
+ if (pkt_ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, pkt_ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid netifcon");
+ return rc;
+}
+
+int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_genfscon *genfs = node->data;
+ struct cil_context *ctx = genfs->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid genfscon");
+ return rc;
+}
+
+int __cil_verify_filecon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_filecon *file = node->data;
+ struct cil_context *ctx = file->context;
+
+ if (ctx == NULL) {
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Invalid filecon");
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+int __cil_verify_nodecon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_nodecon *nodecon = node->data;
+ struct cil_context *ctx = nodecon->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid nodecon");
+ return rc;
+}
+
+int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_portcon *port = node->data;
+ struct cil_context *ctx = port->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid portcon");
+ return rc;
+}
+
+int __cil_verify_pirqcon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_pirqcon *pirq = node->data;
+ struct cil_context *ctx = pirq->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid pirqcon");
+ return rc;
+}
+
+int __cil_verify_iomemcon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_iomemcon *iomem = node->data;
+ struct cil_context *ctx = iomem->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid iomemcon");
+ return rc;
+}
+
+int __cil_verify_ioportcon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_ioportcon *ioport = node->data;
+ struct cil_context *ctx = ioport->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid ioportcon");
+ return rc;
+}
+
+int __cil_verify_pcidevicecon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_pcidevicecon *pcidev = node->data;
+ struct cil_context *ctx = pcidev->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid pcidevicecon");
+ return rc;
+}
+
+int __cil_verify_devicetreecon(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_devicetreecon *dt = node->data;
+ struct cil_context *ctx = dt->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid devicetreecon");
+ return rc;
+}
+
+int __cil_verify_fsuse(struct cil_db *db, struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_fsuse *fsuse = node->data;
+ struct cil_context *ctx = fsuse->context;
+
+ /* Verify only when anonymous */
+ if (ctx->datum.name == NULL) {
+ rc = __cil_verify_context(db, ctx);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid fsuse");
+ return rc;
+}
+
+int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node *node)
+{
+ int rc;
+ struct cil_list *classes = NULL;
+ struct cil_list_item *item;
+ struct cil_class *class;
+ struct cil_symtab_datum *perm_datum;
+ char *kind_str;
+
+ switch (permx->kind) {
+ case CIL_PERMX_KIND_IOCTL:
+ kind_str = CIL_KEY_IOCTL;
+ break;
+ default:
+ cil_tree_log(node, CIL_ERR, "Invalid permissionx kind (%d)", permx->kind);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ classes = cil_expand_class(permx->obj);
+
+ cil_list_for_each(item, classes) {
+ class = item->data;
+ rc = cil_symtab_get_datum(&class->perms, kind_str, &perm_datum);
+ if (rc == SEPOL_ENOENT) {
+ if (class->common != NULL) {
+ rc = cil_symtab_get_datum(&class->common->perms, kind_str, &perm_datum);
+ }
+
+ if (rc == SEPOL_ENOENT) {
+ cil_tree_log(node, CIL_ERR, "Invalid permissionx: %s is not a permission of class %s", kind_str, class->datum.name);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ }
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ if (classes != NULL) {
+ cil_list_destroy(&classes, CIL_FALSE);
+ }
+
+ return rc;
+}
+
+int __cil_verify_avrulex(struct cil_tree_node *node)
+{
+ struct cil_avrule *avrulex = node->data;
+ return __cil_verify_permissionx(avrulex->perms.x.permx, node);
+}
+
+int __cil_verify_class(struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_class *class = node->data;
+
+ if (class->common != NULL) {
+ struct cil_class *common = class->common;
+ struct cil_tree_node *common_node = common->datum.nodes->head->data;
+ struct cil_tree_node *curr_com_perm = NULL;
+
+ for (curr_com_perm = common_node->cl_head;
+ curr_com_perm != NULL;
+ curr_com_perm = curr_com_perm->next) {
+ struct cil_perm *com_perm = curr_com_perm->data;
+ struct cil_tree_node *curr_class_perm = NULL;
+
+ for (curr_class_perm = node->cl_head;
+ curr_class_perm != NULL;
+ curr_class_perm = curr_class_perm->next) {
+ struct cil_perm *class_perm = curr_class_perm->data;
+
+ if (com_perm->datum.name == class_perm->datum.name) {
+ cil_log(CIL_ERR, "Duplicate permissions between %s common and class declarations\n", class_perm->datum.name);
+ goto exit;
+ }
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid class");
+ return rc;
+}
+
+int __cil_verify_policycap(struct cil_tree_node *node)
+{
+ int rc;
+ struct cil_policycap *polcap = node->data;
+
+ rc = sepol_polcap_getnum((const char*)polcap->datum.name);
+ if (rc == SEPOL_ERR) {
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ cil_tree_log(node, CIL_ERR, "Invalid policycap (%s)", (const char*)polcap->datum.name);
+ return rc;
+}
+
+int __cil_verify_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+ int rc = SEPOL_ERR;
+ int *avrule_cnt = 0;
+ int *handleunknown;
+ int *mls;
+ int *nseuserdflt = 0;
+ int *pass = 0;
+ struct cil_args_verify *args = extra_args;
+ struct cil_complex_symtab *csymtab = NULL;
+ struct cil_db *db = NULL;
+
+ if (node == NULL || extra_args == NULL) {
+ goto exit;
+ }
+
+ db = args->db;
+ avrule_cnt = args->avrule_cnt;
+ handleunknown = args->handleunknown;
+ mls = args->mls;
+ nseuserdflt = args->nseuserdflt;
+ csymtab = args->csymtab;
+ pass = args->pass;
+
+ if (node->flavor == CIL_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ } else if (node->flavor == CIL_BLOCK) {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ switch (*pass) {
+ case 0: {
+ switch (node->flavor) {
+ case CIL_USER:
+ rc = __cil_verify_user_post_eval(db, node);
+ break;
+ case CIL_SELINUXUSERDEFAULT:
+ (*nseuserdflt)++;
+ rc = SEPOL_OK;
+ break;
+ case CIL_ROLE:
+ rc = __cil_verify_role(node);
+ break;
+ case CIL_TYPE:
+ rc = __cil_verify_type(node);
+ break;
+ case CIL_AVRULE:
+ (*avrule_cnt)++;
+ rc = SEPOL_OK;
+ break;
+ case CIL_HANDLEUNKNOWN:
+ if (*handleunknown != -1) {
+ cil_log(CIL_ERR, "Policy can not have more than one handleunknown\n");
+ rc = SEPOL_ERR;
+ } else {
+ *handleunknown = ((struct cil_handleunknown*)node->data)->handle_unknown;
+ rc = SEPOL_OK;
+ }
+ break;
+ case CIL_MLS:
+ if (*mls != -1) {
+ cil_log(CIL_ERR, "Policy can not have more than one mls\n");
+ rc = SEPOL_ERR;
+ } else {
+ *mls = ((struct cil_mls*)node->data)->value;
+ rc = SEPOL_OK;
+ }
+ break;
+ case CIL_ROLETRANSITION:
+ rc = SEPOL_OK; //TODO __cil_verify_rule doesn't work quite right
+ //rc = __cil_verify_rule(node, csymtab);
+ break;
+ case CIL_TYPE_RULE:
+ rc = SEPOL_OK; //TODO __cil_verify_rule doesn't work quite right
+ //rc = __cil_verify_rule(node, csymtab);
+ break;
+ case CIL_BOOLEANIF:
+ rc = __cil_verify_booleanif(node, csymtab);
+ *finished = CIL_TREE_SKIP_HEAD;
+ break;
+ case CIL_LEVELRANGE:
+ rc = __cil_verify_named_levelrange(db, node);
+ break;
+ case CIL_CLASS:
+ rc = __cil_verify_class(node);
+ break;
+ case CIL_POLICYCAP:
+ rc = __cil_verify_policycap(node);
+ break;
+ default:
+ rc = SEPOL_OK;
+ break;
+ }
+ break;
+ }
+ case 1: {
+ switch (node->flavor) {
+ case CIL_CONTEXT:
+ rc = __cil_verify_named_context(db, node);
+ break;
+ case CIL_NETIFCON:
+ rc = __cil_verify_netifcon(db, node);
+ break;
+ case CIL_GENFSCON:
+ rc = __cil_verify_genfscon(db, node);
+ break;
+ case CIL_FILECON:
+ rc = __cil_verify_filecon(db, node);
+ break;
+ case CIL_NODECON:
+ rc = __cil_verify_nodecon(db, node);
+ break;
+ case CIL_PORTCON:
+ rc = __cil_verify_portcon(db, node);
+ break;
+ case CIL_PIRQCON:
+ rc = __cil_verify_pirqcon(db, node);
+ break;
+ case CIL_IOMEMCON:
+ rc = __cil_verify_iomemcon(db, node);
+ break;
+ case CIL_IOPORTCON:
+ rc = __cil_verify_ioportcon(db, node);
+ break;
+ case CIL_PCIDEVICECON:
+ rc = __cil_verify_pcidevicecon(db, node);
+ break;
+ case CIL_DEVICETREECON:
+ rc = __cil_verify_devicetreecon(db, node);
+ break;
+ case CIL_FSUSE:
+ rc = __cil_verify_fsuse(db, node);
+ break;
+ case CIL_AVRULEX:
+ rc = __cil_verify_avrulex(node);
+ break;
+ case CIL_PERMISSIONX:
+ rc = __cil_verify_permissionx(node->data, node);
+ break;
+ case CIL_RANGETRANSITION:
+ rc = SEPOL_OK;
+ break;
+ default:
+ rc = SEPOL_OK;
+ break;
+ }
+ break;
+ }
+ default:
+ rc = SEPOL_ERR;
+ }
+
+exit:
+ return rc;
+}
+
+static int __cil_verify_classperms(struct cil_list *classperms, struct cil_symtab_datum *orig)
+{
+ int rc = SEPOL_ERR;
+ struct cil_list_item *curr;
+
+ cil_list_for_each(curr, classperms) {
+ if (curr->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = curr->data;
+ if (FLAVOR(cp->class) == CIL_CLASS) {
+ return SEPOL_OK;
+ } else { /* MAP */
+ struct cil_list_item *i = NULL;
+ cil_list_for_each(i, cp->perms) {
+ struct cil_perm *cmp = i->data;
+ if (&cmp->datum == orig) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ rc = __cil_verify_classperms(cmp->classperms, orig);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+ } else { /* SET */
+ struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classpermission *cp = cp_set->set;
+ if (&cp->datum == orig) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ rc = __cil_verify_classperms(cp->classperms, orig);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+static int __cil_verify_classpermission(struct cil_tree_node *node)
+{
+ int rc = SEPOL_ERR;
+ struct cil_classpermission *cp = node->data;
+
+ if (cp->classperms == NULL) {
+ cil_tree_log(node, CIL_ERR, "Classpermission %s does not have a classpermissionset", cp->datum.name);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = __cil_verify_classperms(cp->classperms, &cp->datum);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Found circular class permissions involving the set %s",cp->datum.name);
+ goto exit;
+ }
+
+ rc = SEPOL_OK;
+
+exit:
+ return rc;
+}
+
+struct cil_verify_map_args {
+ struct cil_class *class;
+ struct cil_tree_node *node;
+ int rc;
+};
+
+static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ int rc = SEPOL_ERR;
+ struct cil_verify_map_args *map_args = args;
+ struct cil_perm *cmp = (struct cil_perm *)d;
+
+ if (cmp->classperms == NULL) {
+ cil_tree_log(map_args->node, CIL_ERR, "Map class %s does not have a classmapping for %s", map_args->class->datum.name, cmp->datum.name);
+ map_args->rc = SEPOL_ERR;
+ goto exit;
+ }
+
+ rc = __cil_verify_classperms(cmp->classperms, &cmp->datum);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(map_args->node, CIL_ERR, "Found circular class permissions involving the map class %s and permission %s", map_args->class->datum.name, cmp->datum.name);
+ map_args->rc = SEPOL_ERR;
+ goto exit;
+ }
+
+exit:
+ return SEPOL_OK;
+}
+
+static int __cil_verify_map_class(struct cil_tree_node *node)
+{
+ struct cil_class *mc = node->data;
+ struct cil_verify_map_args map_args;
+
+ map_args.class = mc;
+ map_args.node = node;
+ map_args.rc = SEPOL_OK;
+
+ cil_symtab_map(&mc->perms, __verify_map_perm_classperms, &map_args);
+
+ if (map_args.rc != SEPOL_OK) {
+ return SEPOL_ERR;
+ }
+
+ return SEPOL_OK;
+}
+
+int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __attribute__((unused)) void *extra_args)
+{
+ int rc = SEPOL_ERR;
+
+ if (node->flavor == CIL_MACRO) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ rc = SEPOL_OK;
+ goto exit;
+ } else if (node->flavor == CIL_BLOCK) {
+ struct cil_block *blk = node->data;
+ if (blk->is_abstract == CIL_TRUE) {
+ *finished = CIL_TREE_SKIP_HEAD;
+ }
+ rc = SEPOL_OK;
+ goto exit;
+ }
+
+ switch (node->flavor) {
+ case CIL_USER:
+ rc = __cil_verify_user_pre_eval(node);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ break;
+ case CIL_MAP_CLASS:
+ rc = __cil_verify_map_class(node);
+ break;
+ case CIL_CLASSPERMISSION:
+ rc = __cil_verify_classpermission(node);
+ break;
+ default:
+ rc = SEPOL_OK;
+ break;
+ }
+
+exit:
+ return rc;
+}
diff --git a/libsepol/cil/src/cil_verify.h b/libsepol/cil/src/cil_verify.h
new file mode 100644
index 0000000..bda1565
--- /dev/null
+++ b/libsepol/cil/src/cil_verify.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CIL_VERIFY_H_
+#define CIL_VERIFY_H_
+
+#include <stdint.h>
+
+#include "cil_internal.h"
+#include "cil_flavor.h"
+#include "cil_tree.h"
+#include "cil_list.h"
+
+enum cil_syntax {
+ CIL_SYN_STRING = 1 << 0,
+ CIL_SYN_LIST = 1 << 1,
+ CIL_SYN_EMPTY_LIST = 1 << 2,
+ CIL_SYN_N_LISTS = 1 << 3,
+ CIL_SYN_N_STRINGS = 1 << 4,
+ CIL_SYN_END = 1 << 5
+};
+
+struct cil_args_verify {
+ struct cil_db *db;
+ struct cil_complex_symtab *csymtab;
+ int *avrule_cnt;
+ int *handleunknown;
+ int *mls;
+ int *nseuserdflt;
+ int *pass;
+};
+
+int __cil_verify_name(const char *name);
+int __cil_verify_syntax(struct cil_tree_node *parse_current, enum cil_syntax s[], int len);
+int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, enum cil_flavor expr_flavor);
+int cil_verify_constraint_leaf_expr_syntax(enum cil_flavor l_flavor, enum cil_flavor r_flavor, enum cil_flavor op, enum cil_flavor expr_flavor);
+int cil_verify_constraint_expr_syntax(struct cil_tree_node *current, enum cil_flavor op);
+int cil_verify_no_self_reference(struct cil_symtab_datum *datum, struct cil_list *datum_list);
+int __cil_verify_ranges(struct cil_list *list);
+int __cil_verify_ordered_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args);
+int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor);
+int __cil_verify_initsids(struct cil_list *sids);
+int __cil_verify_senscat(struct cil_sens *sens, struct cil_cat *cat);
+int __cil_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
+int __cil_pre_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
+
+#endif
diff --git a/libsepol/cil/src/dso.h b/libsepol/cil/src/dso.h
new file mode 100644
index 0000000..a06e349
--- /dev/null
+++ b/libsepol/cil/src/dso.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H 1
+
+#if !defined(SHARED) || defined(ANDROID)
+ #define DISABLE_SYMVER 1
+#endif
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal) \
+ extern __typeof (fct) internal; \
+ extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/libsepol/cil/test/integration_testing/mls_policy.cil b/libsepol/cil/test/integration_testing/mls_policy.cil
new file mode 100644
index 0000000..535ac11
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/mls_policy.cil
@@ -0,0 +1,115 @@
+(class testing (read open close write exec))
+(class fooclass (read open close write exec))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(categoryalias c0 cat)
+(categoryorder (c0 c1 c2 c3 c4))
+(categoryset catset (c0 c2 c3))
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivityalias s3 sens)
+(dominance (s0 s1 s2 s3))
+(sensitivitycategory s0 (c0 c2 c3))
+(sensitivitycategory s0 (cat))
+; the following causes a segfault
+;(sensitivitycategory sens (c2))
+(type foo_t)
+(type typea_t)
+(type typeb_t)
+(type typec_t)
+(role foo_r)
+(role rolea_r)
+(role roleb_r)
+(user foo_u)
+(user user_u)
+(userrole foo_u foo_r)
+(level low (s0 catset))
+(level high (s0 (c0)))
+(level test_l (s0 (cat)))
+
+(sid test_sid)
+(sidcontext test_sid (foo_u foo_r foo_t (s0 (c0)) (s0 (c0))))
+(sid test_sid_anon_l)
+(sidcontext test_sid_anon_l (foo_u foo_r foo_t low high))
+
+(context con (foo_u foo_r foo_t low high))
+(context con_anon_l (foo_u foo_r foo_t (s0 (c0)) high))
+(fsuse xattr ext3 con)
+(fsuse xattr ext3 con_anon_l)
+
+(netifcon eth0 con con_anon_l)
+
+(ipaddr ip_v4 192.25.35.200)
+(ipaddr netmask 192.168.1.1)
+(ipaddr ip_v6 2001:0DB8:AC10:FE01::)
+(ipaddr netmask_v6 2001:0DE0:DA88:2222::)
+; will need anon levels
+(nodecon ip_v4 netmask con)
+(nodecon ip_v6 netmask_v6 con_anon_l)
+
+;needs anon levels
+(portcon type 25 con)
+
+(filecon root path file con)
+
+(genfscon type path con)
+
+(netifcon eth0 con con_anon_l)
+
+(typemember typea_t typeb_t testing typec_t)
+(typechange typea_t typeb_t testing typec_t)
+(typetransition typea_t typeb_t testing typec_t)
+
+(permissionset permset (open close))
+(allow typea_t typeb_t testing (write))
+(allow typea_t typeb_t testing permset)
+
+(roleallow rolea_r roleb_r)
+
+(rolebounds rolea_r roleb_r)
+
+(roletransition foo_r foo_t testing rolea_r)
+
+(level l2 (s0 (c0)))
+(level h2 (s0 (c0)))
+(mlsconstrain (fooclass testing)(open close)(eq l2 h2))
+
+(common fooclass (open))
+(classcommon fooclass fooclass)
+
+(rangetransition typea_t typeb_t fooclass low high)
+
+(nametypetransition string typea_t typeb_t fooclass foo_t)
+
+(typepermissive foo_t)
+
+(typebounds typea_t typeb_t)
+
+(block test_b
+ (typealias .test_b.test typea_t)
+ (type test))
+
+(attribute attrs)
+(attributetypes attrs (foo_t))
+
+(roletype foo_r foo_t)
+
+(userbounds user_u foo_u)
+
+(userrole user_u foo_r)
+
+(bool foo_b true)
+(bool baz_b false)
+(booleanif (&& foo_b baz_b)
+ (allow typea_t typeb_t fooclass(read)))
+;(class baz (read))
+;(booleanif (&& foo_b baz_b)
+; (allow foo_b baz_b fooclass (read)))
+
+
diff --git a/libsepol/cil/test/integration_testing/nonmls.cil b/libsepol/cil/test/integration_testing/nonmls.cil
new file mode 100644
index 0000000..382b95d
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/nonmls.cil
@@ -0,0 +1,86 @@
+(class testing (read open close write exec))
+(class fooclass (read open close write exec))
+
+(type foo_t)
+(type typea_t)
+(type typeb_t)
+(type typec_t)
+(role foo_r)
+(role rolea_r)
+(role roleb_r)
+(user foo_u)
+(user user_u)
+(userrole foo_u foo_r)
+
+(sid test_sid)
+;(sidcontext test_sid (foo_u foo_r foo_t (s0 (c0)) (s0 (c0))))
+;(sid test_sid_anon_l)
+
+;(fsuse xattr ext3 con)
+;(fsuse xattr ext3 con_anon_l)
+
+;(netifcon eth0 con con_anon_l)
+
+(ipaddr ip_v4 192.25.35.200)
+(ipaddr netmask 192.168.1.1)
+(ipaddr ip_v6 2001:0DB8:AC10:FE01::)
+(ipaddr netmask_v6 2001:0DE0:DA88:2222::)
+; will need anon levels
+;(nodecon ip_v4 netmask con)
+;(nodecon ip_v6 netmask_v6 con_anon_l)
+
+;needs anon levels
+;(portcon type 25 con)
+
+;(filecon root path file con)
+
+;(genfscon type path con)
+
+;(netifcon eth0 con con_anon_l)
+
+(typemember typea_t typeb_t testing typec_t)
+(typechange typea_t typeb_t testing typec_t)
+(typetransition typea_t typeb_t testing typec_t)
+
+(permissionset permset (open close))
+(allow typea_t typeb_t testing (write))
+(allow typea_t typeb_t testing permset)
+
+(roleallow rolea_r roleb_r)
+
+(rolebounds rolea_r roleb_r)
+
+(roletransition foo_r foo_t testing rolea_r)
+
+(common fooclass (open))
+(classcommon fooclass fooclass)
+
+
+(nametypetransition string typea_t typeb_t fooclass foo_t)
+
+(typepermissive foo_t)
+
+(typebounds typea_t typeb_t)
+
+(block test_b
+ (typealias .test_b.test typea_t)
+ (type test))
+
+(attribute attrs)
+(attributetypes attrs (foo_t))
+
+(roletype foo_r foo_t)
+
+(userbounds user_u foo_u)
+
+(userrole user_u foo_r)
+
+;(bool foo_b true)
+;(bool baz_b false)
+;(booleanif (&& foo_b baz_b)
+; (allow typea_t typeb_t fooclass(read)))
+;(class baz (read))
+;(booleanif (&& foo_b baz_b)
+; (allow foo_b baz_b fooclass (read)))
+
+
diff --git a/libsepol/cil/test/integration_testing/nonmls.conf b/libsepol/cil/test/integration_testing/nonmls.conf
new file mode 100644
index 0000000..729c7b1
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/nonmls.conf
@@ -0,0 +1,76 @@
+
+class testing
+class fooclass
+
+sid test_sid
+#end
+
+#sid decl
+sid security
+
+
+class testing
+{
+ read
+ open
+ close
+ write
+ exec
+}
+class fooclass
+{
+ read
+ open
+ close
+ write
+ exec
+}
+#end
+
+#attribs
+
+attribute attrs;
+#end
+
+
+type foo_t, attrs;
+type typea_t;
+type typeb_t;
+type typec_t;
+#end
+
+
+bool foo_b true;
+bool baz_b false;
+#end
+
+
+role foo_r types foo_t;
+role rolea_r;
+role roleb_r;
+#end
+
+#role decl
+
+
+allow typea_t typeb_t : testing write;
+allow typea_t typeb_t : testing {open close};
+type_transition typea_t typeb_t : testing typec_t;
+#end
+
+#audit rules
+#dontaudit {kernel} unknown : dir search;
+
+
+allow rolea_r roleb_r;
+#end
+
+#rbac stuff
+#allow system {guest local_user};
+#allow local_user guest;
+
+
+user foo_u roles foo_r;
+#end
+
+sid test_sid foo_u:foo_r:foo_t
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil
new file mode 100644
index 0000000..321fe2f
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad1.cil
@@ -0,0 +1,42 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil
new file mode 100644
index 0000000..9e84191
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad2.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil b/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil
new file mode 100644
index 0000000..36aa687
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_bad3.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_easy.cil b/libsepol/cil/test/integration_testing/ordered_lists_easy.cil
new file mode 100644
index 0000000..36df1e6
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_easy.cil
@@ -0,0 +1,38 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s0 s1 s2 s3 s4 s5 s6 s7 s8 s9))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c2 c3 c4 c5))
+(categoryorder (c0 c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c7 c8 c9))
+
diff --git a/libsepol/cil/test/integration_testing/ordered_lists_hard.cil b/libsepol/cil/test/integration_testing/ordered_lists_hard.cil
new file mode 100644
index 0000000..f00c5b1
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/ordered_lists_hard.cil
@@ -0,0 +1,43 @@
+; Minimum policy
+; ****************************
+
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
+; ****************************
+
+(sensitivity s0)
+(sensitivity s1)
+(sensitivity s2)
+(sensitivity s3)
+(sensitivity s4)
+(sensitivity s5)
+(sensitivity s6)
+(sensitivity s7)
+(sensitivity s8)
+(sensitivity s9)
+(dominance (s2 s3 s4))
+(dominance (s1 s2 s4 s5))
+(dominance (s5 s6 s8))
+(dominance (s6 s7 s8 s9))
+(dominance (s0 s1))
+
+(category c0)
+(category c1)
+(category c2)
+(category c3)
+(category c4)
+(category c5)
+(category c6)
+(category c7)
+(category c8)
+(category c9)
+
+(categoryorder (c1 c3))
+(categoryorder (c1 c2 c3))
+(categoryorder (c5 c6 c7))
+(categoryorder (c3 c4 c5))
+(categoryorder (c7 c8 c9))
+(categoryorder (c0 c1))
diff --git a/libsepol/cil/test/integration_testing/small.cil b/libsepol/cil/test/integration_testing/small.cil
new file mode 100644
index 0000000..9973166
--- /dev/null
+++ b/libsepol/cil/test/integration_testing/small.cil
@@ -0,0 +1,5 @@
+(class foo (read))
+
+(type bar)
+(allow bar self (foo (read)))
+
diff --git a/libsepol/cil/test/unit/AllTests.c b/libsepol/cil/test/unit/AllTests.c
new file mode 100644
index 0000000..40080c8
--- /dev/null
+++ b/libsepol/cil/test/unit/AllTests.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdio.h>
+#include "CuTest.h"
+#include "../../src/cil_log.h"
+
+CuSuite* CilTreeGetSuite(void);
+CuSuite* CilTreeGetResolveSuite(void);
+CuSuite* CilTreeGetBuildSuite(void);
+CuSuite* CilTestFullCil(void);
+
+void RunAllTests(void) {
+ /* disable cil log output */
+ cil_set_log_level(0);
+
+ CuString *output = CuStringNew();
+ CuSuite* suite = CuSuiteNew();
+ CuSuite* suiteResolve = CuSuiteNew();
+ CuSuite* suiteBuild = CuSuiteNew();
+ CuSuite* suiteIntegration = CuSuiteNew();
+
+ CuSuiteAddSuite(suite, CilTreeGetSuite());
+ CuSuiteAddSuite(suiteResolve, CilTreeGetResolveSuite());
+ CuSuiteAddSuite(suiteBuild, CilTreeGetBuildSuite());
+ CuSuiteAddSuite(suiteIntegration, CilTestFullCil());
+
+ CuSuiteRun(suite);
+ CuSuiteDetails(suite, output);
+ CuSuiteSummary(suite, output);
+
+ CuSuiteRun(suiteResolve);
+ CuSuiteDetails(suiteResolve, output);
+ CuSuiteSummary(suiteResolve, output);
+
+ CuSuiteRun(suiteBuild);
+ CuSuiteDetails(suiteBuild, output);
+ CuSuiteSummary(suiteBuild, output);
+
+ CuSuiteRun(suiteIntegration);
+ CuSuiteDetails(suiteIntegration, output);
+ CuSuiteSummary(suiteIntegration, output);
+ printf("\n%s\n", output->buffer);
+}
+
+int main(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[]) {
+ RunAllTests();
+
+ return 0;
+}
diff --git a/libsepol/cil/test/unit/CilTest.c b/libsepol/cil/test/unit/CilTest.c
new file mode 100644
index 0000000..c0c2f3b
--- /dev/null
+++ b/libsepol/cil/test/unit/CilTest.c
@@ -0,0 +1,1974 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+
+#include "test_cil.h"
+#include "test_cil_tree.h"
+#include "test_cil_list.h"
+#include "test_cil_symtab.h"
+#include "test_cil_parser.h"
+#include "test_cil_lexer.h"
+#include "test_cil_build_ast.h"
+#include "test_cil_resolve_ast.h"
+#include "test_cil_fqn.h"
+#include "test_cil_copy_ast.h"
+#include "test_cil_post.h"
+#include "test_integration.h"
+
+void set_cil_file_data(struct cil_file_data **data) {
+ struct cil_file_data *new_data = malloc(sizeof(*new_data));
+ FILE *file;
+ struct stat filedata;
+ uint32_t file_size;
+ char *buffer;
+
+ file = fopen("test/policy.cil", "r");
+ if (!file) {
+ fprintf(stderr, "Could not open file\n");
+ exit(1);
+ }
+ if (stat("test/policy.cil", &filedata) == -1) {
+ printf("Could not stat file\n");
+ exit(1);
+ }
+ file_size = filedata.st_size;
+
+ buffer = malloc(file_size + 2);
+ if(fread(buffer, file_size, 1, file) < 1) {
+ exit(1);
+ }
+ memset(buffer+file_size, 0, 2);
+ fclose(file);
+
+
+ new_data->buffer = buffer;
+ new_data->file_size = file_size;
+
+ *data = new_data;
+
+}
+
+void gen_test_tree(struct cil_tree **test_root, char *line[]) {
+ struct cil_tree *new_tree = malloc(sizeof(*new_tree));
+ struct cil_tree_node *node, *item, *current;
+
+ cil_tree_init(&new_tree);
+ new_tree->root->flavor = CIL_ROOT;
+ current = new_tree->root;
+
+ char **i = line;
+ do {
+ if (*i[0] == '(') {
+ cil_tree_node_init(&node);
+ node->parent = current;
+ node->flavor = CIL_PARSE_NODE;
+ node->line = 0;
+ if (current->cl_head == NULL)
+ current->cl_head = node;
+ else
+ current->cl_tail->next = node;
+ current->cl_tail = node;
+ current = node;
+ }
+ else if (*i[0] == ')')
+ current = current->parent;
+ else {
+ cil_tree_node_init(&item);
+ item->parent = current;
+ item->data = cil_strdup(*i);
+ item->flavor = CIL_PARSE_NODE;
+ item->line = 0;
+ if (current->cl_head == NULL) {
+ current->cl_head = item;
+ }
+ else {
+ current->cl_tail->next = item;
+ }
+ current->cl_tail = item;
+ }
+ i++;
+ } while(*i != NULL);
+
+ *test_root = new_tree;
+}
+
+void test_symtab_init(CuTest *tc) {
+ struct cil_db *test_new_db;
+ test_new_db = malloc(sizeof(*test_new_db));
+
+ uint32_t rc = 0, i =0;
+
+ for (i = 0; i < CIL_SYM_NUM; i++) {
+ rc = symtab_init(&test_new_db->symtab[i], cil_sym_sizes[CIL_SYM_ARRAY_ROOT][i]);
+ CuAssertIntEquals(tc, 0, rc);
+ // TODO CDS add checks to make sure the symtab looks correct
+ }
+
+ free(test_new_db);
+}
+
+void test_symtab_init_no_table_neg(CuTest *tc) {
+ struct cil_db *test_new_db;
+ test_new_db = malloc(sizeof(*test_new_db));
+
+ int rc = symtab_init(&test_new_db->symtab[0], (uint32_t)SIZE_MAX);
+ CuAssertIntEquals(tc, -1, rc);
+
+ free(test_new_db);
+}
+
+CuSuite* CilTreeGetResolveSuite(void) {
+ CuSuite* suite = CuSuiteNew();
+
+ /* test_cil_resolve_ast.c */
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_curr_null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes_inval_perm_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_name);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_invalid_type_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_type_in_multiple_attrs);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_multiple_excludes_with_not);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_multiple_types_with_and);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_using_attr);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_name_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_undef_type_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_not);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typeattributeset_undef_type_not_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typeattributeset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_typealias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typealias_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typealias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typealias_notype_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_typebounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_repeatbind_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_type1_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typebounds_type2_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typebounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typebounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_typepermissive);
+ SUITE_ADD_TEST(suite, test_cil_resolve_typepermissive_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typepermissive);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_typepermissive_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_src_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_tgt_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_class_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nametypetransition_dest_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nametypetransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nametypetransition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_namedrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_type1_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_type2_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_class_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_l_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_l_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_h_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_call_level_h_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_level_l_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_level_h_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_l);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_l_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_h);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rangetransition_anon_level_h_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rangetransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rangetransition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_classcommon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classcommon_no_class_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classcommon_no_common_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_classcommon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_classcommon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_named);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_inmacro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_inmacro_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_named_classmapname_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_classmapname_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classmapping_anon_permset_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_exists_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_role1_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_rolebounds_role2_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rolebounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_rolebounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_sensalias_sensdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sensalias_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_catalias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catalias_catdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catalias);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catalias_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_catorder);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catorder_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catorder);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catorder_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_dominance);
+ SUITE_ADD_TEST(suite, test_cil_resolve_dominance_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_dominance);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_dominance_neg);
+ //TODO: test for __cil_set_order
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_catset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catset_catlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catset_catlist_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_catrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catrange_catloworder_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cathighorder_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cat1_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_catrange_cat2_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_catrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catsetname);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_catsetname_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_sublist);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_missingsens_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_category_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_senscat_currrangecat);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_senscat);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_senscat_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_level);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_catlist);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_catset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_catset_name_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_sens_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_cat_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_level_senscat_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_level);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_level_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl);
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl_low_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_namedlvl_high_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl);
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl_low_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_levelrange_anonlvl_high_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_levelrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_levelrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_constrain);
+ SUITE_ADD_TEST(suite, test_cil_resolve_constrain_class_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_constrain_perm_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_constrain_perm_resolve_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_constrain);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_constrain_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_mlsconstrain);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_mlsconstrain_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_macro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_namedrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_namedrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_user_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_role_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_type_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_context_anon_level_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_context_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletransition_resultdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_roleallow);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roleallow_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roleallow_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roleallow);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roleallow_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_namedpermlist);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_permlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_named_unnamedcps_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon_namedpermlist);
+ SUITE_ADD_TEST(suite, test_cil_resolve_classpermset_anon_permlist_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_permset_permdne_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_firsttype_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_secondtype_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_class_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_avrule_perm_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_src_nores_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_class_nores_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_avrule_datum_null_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_objdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_transition_resultdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_transition);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_transition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_objdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_change_resultdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_change);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_change_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_srcdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_tgtdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_objdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_type_rule_member_resultdecl_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_member);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_type_rule_member_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_filecon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_filecon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_filecon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_filecon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_filecon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_filecon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_portcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_portcon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_portcon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_portcon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_portcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_portcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_genfscon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_genfscon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_genfscon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_genfscon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipv4);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipv6);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonipaddr_ipv4);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonnetmask_ipv4);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonipaddr_ipv6);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anonnetmask_ipv6);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_diffipfam_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_ipaddr_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_netmask_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_nodecon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodecon_netmask_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_otf_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_interface_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed);
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed_packet_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_netifcon_unnamed_otf_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_netifcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_netifcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pirqcon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pirqcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pirqcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_iomemcon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_iomemcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_iomemcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ioportcon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_ioportcon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_ioportcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_pcidevicecon_anon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pcidevicecon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_pcidevicecon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_fsuse);
+ SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_fsuse_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_fsuse);
+ //SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_fsuse_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext);
+ SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_levels);
+ SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context);
+ SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context_wrongname_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_sidcontext_named_context_invaliduser_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sidcontext);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_sidcontext_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_blockinherit);
+ SUITE_ADD_TEST(suite, test_cil_resolve_blockinherit_blockstrdne_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_blockinherit);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_in_block);
+ SUITE_ADD_TEST(suite, test_cil_resolve_in_blockstrdne_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_in_macro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_in_optional);
+
+ //SUITE_ADD_TEST(suite, test_cil_resolve_call1_noparam);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_type);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_role);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_user);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_sens);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_cat);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_catset_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_class);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_classmap);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_permset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_permset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_named);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_classpermset_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_level);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_level_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_level_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_ipaddr_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknown_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknowncall_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_extraargs_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_copy_dup);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_missing_arg_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_paramsflavor_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call1_unknownflavor_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call1);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call1_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_type);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_role);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_user);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_sens);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_cat);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_catset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_catset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_permset);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_permset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_classpermset_named);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_classpermset_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_class);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_classmap);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_level);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_level_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_ipaddr_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_call2_unknown_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call2);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call2_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_multipleparams);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_diffflavor);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_callnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_namenull_neg);
+ //SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_callargsnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_name_call_args_name_neg);
+
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_bools);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_tunables);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_type);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_role);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_user);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_neg);
+// SUITE_ADD_TEST(suite, test_cil_resolve_expr_stack_emptystr_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_boolif);
+ SUITE_ADD_TEST(suite, test_cil_resolve_boolif_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_boolif);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_boolif_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_and);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_not);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_or);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_xor);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_eq);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_neq);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_oper1);
+ SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_oper2);
+ //SUITE_ADD_TEST(suite, test_cil_evaluate_expr_stack_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_tunif_false);
+ SUITE_ADD_TEST(suite, test_cil_resolve_tunif_true);
+ SUITE_ADD_TEST(suite, test_cil_resolve_tunif_resolveexpr_neg);
+ //SUITE_ADD_TEST(suite, test_cil_resolve_tunif_evaluateexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_tunif);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_tunif_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_userbounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_exists_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_user1_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userbounds_user2_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userbounds);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userbounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletype);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletype_type_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_roletype_role_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype_role_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_roletype_type_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrole);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrole_user_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrole_role_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole_user_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrole_role_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_macro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_user_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userlevel_level_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userlevel);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userlevel_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_macro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_anon);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_anon_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_user_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_userrange_range_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrange);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_userrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_optional_enabled);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_optional_disabled);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_block);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_user);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_role);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_type);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_typealias);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_common);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_class);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_bool);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sens);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_cat);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_catset);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sid);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_macro);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_context);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_level);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_policycap);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_perm);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_catalias);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_tunable);
+ SUITE_ADD_TEST(suite, test_cil_disable_children_helper_unknown);
+
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_callstack);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_call);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optional);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_macro);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack_tunable_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optstack_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_nodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_extraargsnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_resolve_ast_node_helper_optfailedtoresolve);
+
+ return suite;
+}
+
+CuSuite* CilTreeGetBuildSuite(void) {
+ CuSuite* suite = CuSuiteNew();
+
+ /* test_cil_build_ast.c */
+ SUITE_ADD_TEST(suite, test_cil_build_ast);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_treenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_suberr_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_parse_to_list);
+ SUITE_ADD_TEST(suite, test_cil_parse_to_list_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_parse_to_list_listnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_set_to_list);
+ SUITE_ADD_TEST(suite, test_cil_set_to_list_listnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_set_to_list_tree_node_null_neg);
+ SUITE_ADD_TEST(suite, test_cil_set_to_list_cl_head_null_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_block);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_justblock_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_treenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_nodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_block_nodeparentnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_block);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_block_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_namelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_namenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_blockinherit_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_blockinherit);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_blockinherit_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_perm);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_nodenull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_permset);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_noperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_emptyperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_permset_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_permset);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_permset_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes);
+ SUITE_ADD_TEST(suite, test_cil_gen_perm_nodes_failgen_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_fill_permset);
+ SUITE_ADD_TEST(suite, test_cil_fill_permset_sublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_permset_startpermnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_permset_permsetnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_in);
+ SUITE_ADD_TEST(suite, test_cil_gen_in_blockstrnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_in_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_in_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_in_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_in_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_in);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_in_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_class);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_nodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_noclassname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_namesublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_noperms);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_permsnotinlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_extrapermlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_class_listinlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_class);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_class_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_anonperms);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_anonperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_namedperms);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_emptypermslist_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_noperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_classnodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_classpermset_cpsnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_noperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_emptyperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classpermset_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classpermset);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classpermset_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_dupeperm_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_perm_astnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_emptyperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmap_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmap);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmap_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_anonpermset);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_anonpermset_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_namedpermset);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_noclassmapname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_noclassmapperm_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_nopermissionsets_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classmapping_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmapping);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_classmapping_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_common);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_twoperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_permsublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_common_noperms_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_common);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_common_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_sid);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sid_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sid);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sid_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_namedcontext);
+// SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_halfcontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_empty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_dblname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_pcurrnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sidcontext_astnodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sidcontext);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sidcontext_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_type);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattribute);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattribute_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattribute);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattribute_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_notype1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_type1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_notype2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_type2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typebounds_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typebounds);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typebounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_typeinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typepermissive_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typepermissive);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typepermissive_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nostr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_strinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nosrc_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_srcinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_notgt_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_tgtinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_classinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_nodest_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_destinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nametypetransition_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_nametypetransition);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_nametypetransition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_namedtransition);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_low_l);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_low_l_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_high_l);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_anon_high_l_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nofirsttype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_firsttype_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nosecondtype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_secondtype_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_class_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nolevel_l_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_nolevel_h_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rangetransition_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rangetransition);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rangetransition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_and);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_or);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_xor);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not_noexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_not_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_eq);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_neq);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_emptyargs_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_nested_missingoperator_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_arg1null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_arg2null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_extraarg_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_expr_stack_stacknull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_multiplebools_unknowncond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_unknowncond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_nested);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_nested_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_extra_parens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_nocond);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_nocond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_notruelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_boolif_empty_cond_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_boolif);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_boolif_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_multiplebools_unknowncond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_unknowncond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_nocond);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_nested);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_nested_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_extra_parens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_nocond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_tunif_notruelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_tunif);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_tunif_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_nocond_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_condblock_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_true);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_true_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_false);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_condblock_false_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_incomplete_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_incomplete_neg2);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_extratype_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typealias);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typealias_notype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typealias_astnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_and_two_types);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_not);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_exclude_attr);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_exclude_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_emptylists_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_listinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_typeattributeset_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattributeset);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_typeattributeset_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_notype1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_type1_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_notype2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_type2_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userbounds_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userbounds);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userbounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_role);
+ SUITE_ADD_TEST(suite, test_cil_gen_role_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_role_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_role_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_role_extrarole_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_role_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_role);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_role_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_srcnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_tgtnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_resultnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletransition_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletransition);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletransition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_tunable_true);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_tunable_false);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_none_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_notbool_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_boolname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_extraname_false_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_bool_extraname_true_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_tunable);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_bool_tunable_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1type);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1t1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t2type);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t2t2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1role);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1r1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r2role);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r2r2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_t1t2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_r1r2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_r1r2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1u2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1user);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u1u1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u2user);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_u2u2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l2h2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1h1);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1h2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1l2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1h2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_h1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_noexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_emptyparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_not_extraparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_noexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_or_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_noexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_and_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_dom_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_domby_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_stacknull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_operatorinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expr_stack_incorrectcall_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_srcnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_tgtnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roleallow_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roleallow);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roleallow_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_norole1_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_role1_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_norole2_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_role2_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_rolebounds_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rolebounds);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_rolebounds_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_permset);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_permset_anon);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourceparens);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourceemptyparen_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetparens);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetemptyparen_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_sourcedomainnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_targetdomainnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_objectclassnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_permsnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_avrule_twolists_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_allow);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_allow_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_auditallow);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_auditallow_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_dontaudit);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_dontaudit_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_neverallow);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_avrule_neverallow_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_srcnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_tgtnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_objnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_resultnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_transition_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_transition);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_transition_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_srcnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_tgtnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_objnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_resultnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_change_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_change);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_change_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_srcnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_tgtnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_objnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_resultnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_type_rule_member_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_member);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_type_rule_member_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_user);
+ SUITE_ADD_TEST(suite, test_cil_gen_user_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_user_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_user_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_user_nouser_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_user_xsinfo_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_user);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_user_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_anon_level);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_anon_level_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_usernull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_userrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_levelnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_levelrangeempty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userlevel_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userlevel);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userlevel_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_named);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_anon);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_usernull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonuser_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_rangenamenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonrangeinvalid_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_anonrangeempty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrange_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrange);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_sensnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_senslist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensitivity_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensitivity);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensitivity_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_sensnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_senslist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_aliasnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_aliaslist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_sensalias_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_sensalias_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_category);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_catnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_catlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_category_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_category);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_category_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_catset);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_namenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_setnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_namelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_nodefail_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_notset_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catset_settolistfail_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catset);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catset_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_catnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_aliasnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catalias_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catalias);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catalias_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_norange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_emptyrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_extrarange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catrange_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catrange);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_empty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_rolelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_roletype_sublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_roletype_typelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletype);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_roletype_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_empty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_userlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_userrole_sublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_userrole_rolelist_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrole);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_userrole_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_missingclassname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_noperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_classcommon_extraperms_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_classcommon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_classcommon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_missingcats_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_nosublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_catorder_nestedcat_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catorder);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_catorder_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance);
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance_nosensitivities_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_dominance_nosublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_dominance);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_dominance_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_nosublist);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_nosensitivities_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_sublist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_senscat_nocat_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_senscat);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_senscat_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_fill_level);
+ SUITE_ADD_TEST(suite, test_cil_fill_level_sensnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_level_levelnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_level_nocat);
+ SUITE_ADD_TEST(suite, test_cil_fill_level_emptycat_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_level);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_emptysensparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_emptycat_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_nosens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_level_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_level);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_level_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangeinvalid_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_namenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_rangeempty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_levelrange_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_levelrange);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_levelrange_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_noperm_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_classset_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_noclass_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_permset_noperm_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_expression_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_constrain_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_constrain);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_constrain_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_mlsconstrain);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_mlsconstrain_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_fill_context);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_nouser_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_norole_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_notype_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_nolowlvl_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_nohighlvl_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl_nocontextlow_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_context_unnamedlvl_nocontexthigh_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_context);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_notinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_extralevel_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_emptycontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_doubleparen_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_norole_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_roleinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_notype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_typeinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_nolevels_neg);
+// SUITE_ADD_TEST(suite, test_cil_gen_context_nosecondlevel_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_nouser_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_context_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_context);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_context_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_file);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_dir);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_char);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_block);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_socket);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_pipe);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_symlink);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_any);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_str1null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_str1_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_str2null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_str2_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_classnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_class_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_contextnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_filecon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_filecon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_filecon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_udp);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_tcp);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_unknownprotocol_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange_one_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_portrange_morethanone_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_singleport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_lowport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_highport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_str1null_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_str1parens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_portnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_contextnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_portcon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_portcon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_portcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_fill_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrnodenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_addrinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_fill_ipaddr_extra_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipanon);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_ipanon_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmasknull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmaskanon);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_netmaskanon_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_contextnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_nodecon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_nodecon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_nodecon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_anon_context);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_typenull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_typeparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_pathnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_pathparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_contextnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_context_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_genfscon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_genfscon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_genfscon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_emptysecondlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_extra_nested_secondlist_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_missingobjects_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_nested_secondnested_missingobjects_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_ethmissing_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_interfacemissing_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_netifcon_packetmissing_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_netifcon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_netifcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_pirqnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_nopirq_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_pirqrange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_anoncontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pirqcon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pirqcon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pirqcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_firstnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_secondnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_empty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_singleiomem_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_iomemnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_noiomem_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_anoncontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_iomemcon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_iomemcon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_iomemcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_firstnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_secondnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_empty_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_singleioport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_ioportnotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_noioport_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_anoncontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ioportcon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ioportcon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ioportcon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_pcidevicenotint_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_nopcidevice_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_pcidevicerange_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_anoncontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_pcidevicecon_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pcidevicecon);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_pcidevicecon_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_anoncontext);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_anoncontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_xattr);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_task);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_transition);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_invalidtype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_notype_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_typeinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_nofilesystem_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_filesysteminparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_nocontext_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_emptyconparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_fsuse_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_fsuse);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_fsuse_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_noparams);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_type);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_role);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_user);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_sensitivity);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_category);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_catset);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_level);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_class);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_classmap);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_permset);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_duplicate);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_duplicate_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_unknown_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_unnamed_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_noparam_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_nosecondparam_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_noparam_name_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_emptyparam_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_macro_paramcontainsperiod_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_nested_macro_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_call);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_noargs);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_anon);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_empty_call_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_name_inparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_call_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_call);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_call_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_optional);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_emptyoptional);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_unnamed_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_optional_norule_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_optional);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_optional_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_policycap_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_policycap);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_policycap_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv4);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv4_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv6);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipv6_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_noname_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_nameinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_noip_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_ipinparens_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_extra_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_dbnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_currnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_gen_ipaddr_astnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_gen_ipaddr_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_build_ast_node_helper_extraargsnull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_build_ast_last_child_helper);
+ SUITE_ADD_TEST(suite, test_cil_build_ast_last_child_helper_extraargsnull_neg);
+
+ return suite;
+}
+
+CuSuite* CilTreeGetSuite(void) {
+ CuSuite* suite = CuSuiteNew();
+
+ /* CilTest.c */
+ SUITE_ADD_TEST(suite, test_symtab_init);
+ SUITE_ADD_TEST(suite, test_symtab_init_no_table_neg);
+
+
+ /* test_cil.c */
+ SUITE_ADD_TEST(suite, test_cil_symtab_array_init);
+
+ SUITE_ADD_TEST(suite, test_cil_db_init);
+
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_block);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_class);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_root);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_flavor_neg);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_null_neg);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_node_null_neg);
+ SUITE_ADD_TEST(suite, test_cil_get_symtab_parent_null_neg);
+
+
+ /* test_cil_list.c */
+ SUITE_ADD_TEST(suite, test_cil_list_append_item);
+ SUITE_ADD_TEST(suite, test_cil_list_append_item_append);
+ SUITE_ADD_TEST(suite, test_cil_list_append_item_append_extra);
+ SUITE_ADD_TEST(suite, test_cil_list_append_item_listnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_list_append_item_itemnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_list_prepend_item_prepend);
+ SUITE_ADD_TEST(suite, test_cil_list_prepend_item_prepend_neg);
+ SUITE_ADD_TEST(suite, test_cil_list_prepend_item_listnull_neg);
+ SUITE_ADD_TEST(suite, test_cil_list_prepend_item_itemnull_neg);
+
+
+ /* test_cil_symtab.c */
+ SUITE_ADD_TEST(suite, test_cil_symtab_insert);
+
+
+ /* test_cil_tree.c */
+ SUITE_ADD_TEST(suite, test_cil_tree_init);
+ SUITE_ADD_TEST(suite, test_cil_tree_node_init);
+
+
+ /* test_cil_lexer.c */
+ SUITE_ADD_TEST(suite, test_cil_lexer_setup);
+ SUITE_ADD_TEST(suite, test_cil_lexer_next);
+
+
+ /* test_cil_parser.c */
+ SUITE_ADD_TEST(suite, test_cil_parser);
+
+
+ /* test_cil_fqn.c */
+ SUITE_ADD_TEST(suite, test_cil_qualify_name);
+ SUITE_ADD_TEST(suite, test_cil_qualify_name_cil_flavor);
+
+ /* test cil_copy_ast.c */
+ SUITE_ADD_TEST(suite, test_cil_copy_list);
+ SUITE_ADD_TEST(suite, test_cil_copy_list_sublist);
+ SUITE_ADD_TEST(suite, test_cil_copy_list_sublist_extra);
+ SUITE_ADD_TEST(suite, test_cil_copy_list_orignull_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_block);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_block);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_block_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_perm);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_perm);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_perm_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_class);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_class);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_class_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_common);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_common);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_common_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_classcommon);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_classcommon);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_sid);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sid);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sid_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_sidcontext);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sidcontext);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_user);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_user);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_user_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_role);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_role);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_role_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_userrole);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_userrole);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_type);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_typeattribute);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typeattribute);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typeattribute_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_typealias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typealias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_typealias_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_bool);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_bool);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_bool_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_avrule);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_avrule);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_type_rule);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_type_rule);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_sens);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sens);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sens_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sensalias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_sensalias_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_cat);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_cat);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_cat_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_catalias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catalias);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catalias_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_senscat);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_senscat);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_catorder);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_catorder);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_dominance);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_dominance);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_level);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_level);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_level_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_fill_level);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_context);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_context);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_context_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_netifcon);
+ SUITE_ADD_TEST(suite, test_cil_copy_netifcon_nested);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_netifcon);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_fill_context);
+ SUITE_ADD_TEST(suite, test_cil_copy_fill_context_anonrange);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_call);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_call);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_optional);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_optional);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_optional_merge);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_nodecon);
+ SUITE_ADD_TEST(suite, test_cil_copy_nodecon_anon);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_fill_ipaddr);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_ipaddr);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_ipaddr_dup_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_conditional);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_boolif);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_boolif);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_constrain);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_mlsconstrain);
+
+ //SUITE_ADD_TEST(suite, test_cil_copy_ast);
+ //SUITE_ADD_TEST(suite, test_cil_copy_ast_neg);
+
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_orignull_neg);
+ SUITE_ADD_TEST(suite, test_cil_copy_node_helper_extraargsnull_neg);
+
+ /* test_post.c */
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_not_b);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_b_not_a);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_type_atype_greater_btype);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_type_btype_greater_atype);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_stemlen_a_greater_b);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_stemlen_b_greater_a);
+ SUITE_ADD_TEST(suite, test_cil_post_filecon_compare_equal);
+
+ SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_atypestr_greater_btypestr);
+ SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_btypestr_greater_atypestr);
+ SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_apathstr_greater_bpathstr);
+ SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_bpathstr_greater_apathstr);
+ SUITE_ADD_TEST(suite, test_cil_post_genfscon_compare_equal);
+
+ SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_a_greater_b);
+ SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_b_greater_a);
+ SUITE_ADD_TEST(suite, test_cil_post_netifcon_compare_equal);
+
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_bipv6);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_bipv4);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv4_lessthan_bipv4);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_aipv6_lessthan_bipv6);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6);
+ SUITE_ADD_TEST(suite, test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6);
+
+ SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_type_a_greater_b);
+ SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_type_b_greater_a);
+ SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_fsstr_a_greater_b);
+ SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_fsstr_b_greater_a);
+ SUITE_ADD_TEST(suite, test_cil_post_fsuse_compare_equal);
+
+ return suite;
+}
+
+CuSuite* CilTestFullCil(void) {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_min_policy);
+ SUITE_ADD_TEST(suite, test_integration);
+
+ return suite;
+}
diff --git a/libsepol/cil/test/unit/CilTest.h b/libsepol/cil/test/unit/CilTest.h
new file mode 100644
index 0000000..f43b0ed
--- /dev/null
+++ b/libsepol/cil/test/unit/CilTest.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef CILTEST_H_
+#define CILTEST_H_
+
+#include "../../src/cil_tree.h"
+
+// TODO Check more in the data structures
+struct cil_file_data {
+ char *buffer;
+ uint32_t file_size;
+};
+
+void set_cil_file_data(struct cil_file_data **);
+void gen_test_tree(struct cil_tree **, char **);
+
+#endif
diff --git a/libsepol/cil/test/unit/CuTest.c b/libsepol/cil/test/unit/CuTest.c
new file mode 100644
index 0000000..9b481e3
--- /dev/null
+++ b/libsepol/cil/test/unit/CuTest.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+ char* newStr = (char*) malloc( sizeof(char) * (size) );
+ return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+ int len = strlen(old);
+ char* newStr = CuStrAlloc(len + 1);
+ strcpy(newStr, old);
+ return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void)
+{
+ CuString* str = (CuString*) malloc(sizeof(CuString));
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+ return str;
+}
+
+void CuStringDelete(CuString *str)
+{
+ if (!str) return;
+ free(str->buffer);
+ free(str);
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+ str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+ str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+ int length;
+
+ if (text == NULL) {
+ text = "NULL";
+ }
+
+ length = strlen(text);
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ str->length += length;
+ strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+ char text[2];
+ text[0] = ch;
+ text[1] = '\0';
+ CuStringAppend(str, text);
+}
+
+__attribute__ ((format (printf, 2, 3))) void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+ va_list argp;
+ char buf[HUGE_STRING_LEN];
+ va_start(argp, format);
+ vsprintf(buf, format, argp);
+ va_end(argp);
+ CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+ int length = strlen(text);
+ if (pos > str->length)
+ pos = str->length;
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+ str->length += length;
+ memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+ t->name = CuStrCopy(name);
+ t->failed = 0;
+ t->ran = 0;
+ t->message = NULL;
+ t->function = function;
+ t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+ CuTest* tc = CU_ALLOC(CuTest);
+ CuTestInit(tc, name, function);
+ return tc;
+}
+
+void CuTestDelete(CuTest *t)
+{
+ if (!t) return;
+ free(t->name);
+ free(t);
+}
+
+void CuTestRun(CuTest* tc)
+{
+ jmp_buf buf;
+ tc->jumpBuf = &buf;
+ if (setjmp(buf) == 0)
+ {
+ tc->ran = 1;
+ (tc->function)(tc);
+ }
+ tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+ char buf[HUGE_STRING_LEN];
+
+ sprintf(buf, "%s:%d: ", file, line);
+ CuStringInsert(string, buf, 0);
+
+ tc->failed = 1;
+ tc->message = string->buffer;
+ if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+ CuString string;
+
+ CuStringInit(&string);
+ if (message2 != NULL)
+ {
+ CuStringAppend(&string, message2);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, message);
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+ if (condition) return;
+ CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, const char* actual)
+{
+ CuString string;
+ if ((expected == NULL && actual == NULL) ||
+ (expected != NULL && actual != NULL &&
+ strcmp(expected, actual) == 0))
+ {
+ return;
+ }
+
+ CuStringInit(&string);
+ if (message != NULL)
+ {
+ CuStringAppend(&string, message);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, "expected <");
+ CuStringAppend(&string, expected);
+ CuStringAppend(&string, "> but was <");
+ CuStringAppend(&string, actual);
+ CuStringAppend(&string, ">");
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ int expected, int actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ double expected, double actual, double delta)
+{
+ char buf[STRING_MAX];
+ if (fabs(expected - actual) <= delta) return;
+ sprintf(buf, "expected <%f> but was <%f>", expected, actual);
+
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ void* expected, void* actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+ testSuite->count = 0;
+ testSuite->failCount = 0;
+ memset(testSuite->list, 0, sizeof(testSuite->list));
+}
+
+CuSuite* CuSuiteNew(void)
+{
+ CuSuite* testSuite = CU_ALLOC(CuSuite);
+ CuSuiteInit(testSuite);
+ return testSuite;
+}
+
+void CuSuiteDelete(CuSuite *testSuite)
+{
+ unsigned int n;
+ for (n=0; n < MAX_TEST_CASES; n++)
+ {
+ if (testSuite->list[n])
+ {
+ CuTestDelete(testSuite->list[n]);
+ }
+ }
+ free(testSuite);
+
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+ assert(testSuite->count < MAX_TEST_CASES);
+ testSuite->list[testSuite->count] = testCase;
+ testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+ int i;
+ for (i = 0 ; i < testSuite2->count ; ++i)
+ {
+ CuTest* testCase = testSuite2->list[i];
+ CuSuiteAdd(testSuite, testCase);
+ }
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuTestRun(testCase);
+ if (testCase->failed) { testSuite->failCount += 1; }
+ }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuStringAppend(summary, testCase->failed ? "F" : ".");
+ }
+ CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+ int i;
+ int failCount = 0;
+
+ if (testSuite->failCount == 0)
+ {
+ int passCount = testSuite->count - testSuite->failCount;
+ const char* testWord = passCount == 1 ? "test" : "tests";
+ CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+ }
+ else
+ {
+ if (testSuite->failCount == 1)
+ CuStringAppend(details, "There was 1 failure:\n");
+ else
+ CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ if (testCase->failed)
+ {
+ failCount++;
+ CuStringAppendFormat(details, "%d) %s: %s\n",
+ failCount, testCase->name, testCase->message);
+ }
+ }
+ CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+ CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
+ CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+ CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
+ }
+}
diff --git a/libsepol/cil/test/unit/CuTest.h b/libsepol/cil/test/unit/CuTest.h
new file mode 100644
index 0000000..c5ed90f
--- /dev/null
+++ b/libsepol/cil/test/unit/CuTest.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+
+#define CUTEST_VERSION "CuTest 1.5"
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN 8192
+#define STRING_MAX 256
+#define STRING_INC 256
+
+typedef struct
+{
+ int length;
+ int size;
+ char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+void CuStringDelete(CuString* str);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+ char* name;
+ TestFunction function;
+ int failed;
+ int ran;
+ const char* message;
+ jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+void CuTestDelete(CuTest *t);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+ int count;
+ CuTest* list[MAX_TEST_CASES];
+ int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteDelete(CuSuite *testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
diff --git a/libsepol/cil/test/unit/test_cil.c b/libsepol/cil/test/unit/test_cil.c
new file mode 100644
index 0000000..7b57525
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_tree.h"
+
+void test_cil_symtab_array_init(CuTest *tc) {
+ struct cil_db *test_new_db;
+ test_new_db = malloc(sizeof(*test_new_db));
+
+ cil_symtab_array_init(test_new_db->symtab, cil_sym_sizes[CIL_SYM_ARRAY_ROOT]);
+ CuAssertPtrNotNull(tc, test_new_db->symtab);
+
+ free(test_new_db);
+}
+
+void test_cil_db_init(CuTest *tc) {
+ struct cil_db *test_db;
+
+ cil_db_init(&test_db);
+
+ CuAssertPtrNotNull(tc, test_db->ast);
+ CuAssertPtrNotNull(tc, test_db->symtab);
+ CuAssertPtrNotNull(tc, test_db->symtab);
+}
+
+// TODO: Reach SEPOL_ERR return in cil_db_init ( currently can't produce a method to do so )
+
+void test_cil_get_symtab_block(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->parent->flavor = CIL_BLOCK;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_class(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->parent->flavor = CIL_CLASS;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_root(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->parent->flavor = CIL_ROOT;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, symtab);
+}
+
+void test_cil_get_symtab_flavor_neg(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->parent->flavor = 1234567;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertPtrEquals(tc, symtab, NULL);
+}
+
+void test_cil_get_symtab_null_neg(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = NULL;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertPtrEquals(tc, symtab, NULL);
+}
+
+void test_cil_get_symtab_node_null_neg(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_get_symtab(test_db, test_ast_node, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertPtrEquals(tc, symtab, NULL);
+ CuAssertPtrEquals(tc, test_ast_node, NULL);
+}
+
+void test_cil_get_symtab_parent_null_neg(CuTest *tc) {
+ symtab_t *symtab = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = NULL;
+ test_ast_node->line = 1;
+
+ int rc = cil_get_symtab(test_db, test_ast_node->parent, &symtab, CIL_SYM_BLOCKS);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertPtrEquals(tc, symtab, NULL);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil.h b/libsepol/cil/test/unit/test_cil.h
new file mode 100644
index 0000000..285b4ff
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_H_
+#define TEST_CIL_H_
+
+#include "CuTest.h"
+
+void test_cil_symtab_array_init(CuTest *);
+void test_cil_symtab_array_init_null_symtab_neg(CuTest *);
+void test_cil_db_init(CuTest *);
+void test_cil_get_symtab_block(CuTest *);
+void test_cil_get_symtab_class(CuTest *);
+void test_cil_get_symtab_root(CuTest *);
+void test_cil_get_symtab_flavor_neg(CuTest *);
+void test_cil_get_symtab_null_neg(CuTest *);
+void test_cil_get_symtab_node_null_neg(CuTest *);
+void test_cil_get_symtab_parent_null_neg(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_build_ast.c b/libsepol/cil/test/unit/test_cil_build_ast.c
new file mode 100644
index 0000000..f8cef71
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_build_ast.c
@@ -0,0 +1,19179 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_build_ast.h"
+
+#include "../../src/cil_build_ast.h"
+
+#include "../../src/cil_tree.h"
+
+int __cil_build_ast_node_helper(struct cil_tree_node *, uint32_t *, void *);
+int __cil_build_ast_last_child_helper(__attribute__((unused)) struct cil_tree_node *parse_current, void *);
+//int __cil_build_constrain_tree(struct cil_tree_node *parse_current, struct cil_tree_node *expr_root);
+
+struct cil_args_build {
+ struct cil_tree_node *ast;
+ struct cil_db *db;
+ struct cil_tree_node *macro;
+ struct cil_tree_node *tifstack;
+};
+
+struct cil_args_build *gen_build_args(struct cil_tree_node *node, struct cil_db *db, struct cil_tree_node * macro, struct cil_tree_node *tifstack)
+{
+ struct cil_args_build *args = cil_malloc(sizeof(*args));
+ args->ast = node;
+ args->db = db;
+ args->macro = macro;
+ args->tifstack = tifstack;
+
+ return args;
+}
+
+// First seen in cil_gen_common
+void test_cil_parse_to_list(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_avrule *test_avrule;
+ cil_avrule_init(&test_avrule);
+ test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+ test_avrule->src_str = cil_strdup(test_current->next->data);
+ test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+ cil_classpermset_init(&test_avrule->classpermset);
+
+ test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+ cil_permset_init(&test_avrule->classpermset->permset);
+
+ cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+
+ test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+ int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_parse_to_list_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_avrule *test_avrule;
+ cil_avrule_init(&test_avrule);
+ test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+ test_avrule->src_str = cil_strdup(test_current->next->data);
+ test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+ cil_classpermset_init(&test_avrule->classpermset);
+
+ test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+ cil_permset_init(&test_avrule->classpermset->permset);
+
+ cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+
+ test_current = NULL;
+
+ int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+ cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_parse_to_list_listnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_avrule *test_avrule;
+ cil_avrule_init(&test_avrule);
+ test_avrule->rule_kind = CIL_AVRULE_ALLOWED;
+ test_avrule->src_str = cil_strdup(test_current->next->data);
+ test_avrule->tgt_str = cil_strdup(test_current->next->next->data);
+
+ cil_classpermset_init(&test_avrule->classpermset);
+
+ test_avrule->classpermset->class_str = cil_strdup(test_current->next->next->next->cl_head->data);
+
+ cil_permset_init(&test_avrule->classpermset->permset);
+
+ test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+ int rc = cil_parse_to_list(test_current, test_avrule->classpermset->permset->perms_list_str, CIL_AST_STR);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+ cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_set_to_list(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ struct cil_list *cil_l = NULL;
+ struct cil_list *sub_list = NULL;
+
+ gen_test_tree(&test_tree, line);
+ cil_list_init(&cil_l);
+
+ int rc = cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+ sub_list = (struct cil_list *)cil_l->head->next->next->data;
+
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertStrEquals(tc, "foo1", (char*)cil_l->head->data);
+ CuAssertStrEquals(tc, "foo2", (char*)cil_l->head->next->data);
+ CuAssertStrEquals(tc, "foo3", (char*)sub_list->head->data);
+}
+
+void test_cil_set_to_list_tree_node_null_neg(CuTest *tc) {
+ struct cil_list *cil_l = NULL;
+ int rc = cil_set_to_list(NULL, cil_l, 1);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_set_to_list_cl_head_null_neg(CuTest *tc) {
+ char *line[] = {"(", "foo", "bar", ")", NULL};
+
+ struct cil_list *cil_l;
+ struct cil_tree *test_tree = NULL;
+
+ cil_list_init(&cil_l);
+ gen_test_tree(&test_tree, line);
+ test_tree->root->cl_head = NULL;
+
+ int rc = cil_set_to_list(test_tree->root, cil_l, 1);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_set_to_list_listnull_neg(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", "foo3", ")", NULL};
+
+ struct cil_tree *test_tree = NULL;
+ gen_test_tree(&test_tree, line);
+
+ int rc = cil_set_to_list(test_tree->root, NULL, 1);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, ((struct cil_block*)test_ast_node->data)->is_abstract, 0);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BLOCK);
+}
+
+void test_cil_gen_block_justblock_neg(CuTest *tc) {
+ char *line[] = {"(", "block", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_treenull_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_tree->root->cl_head->cl_head = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_nodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_block_nodeparentnull_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "foo", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = NULL;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_destroy_block(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+
+ cil_destroy_block((struct cil_block*)test_ast_node->data);
+ CuAssertPtrEquals(tc, NULL,test_ast_node->data);
+}
+
+void test_cil_gen_blockinherit(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_blockinherit_namelist_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_namenull_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_blockinherit_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "foo", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_blockinherit(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_class *new_node;
+ cil_class_init(&new_node);
+
+ struct cil_tree_node *new_tree_node;
+ cil_tree_node_init(&new_tree_node);
+ new_tree_node->data = new_node;
+ new_tree_node->flavor = CIL_CLASS;
+
+ test_ast_node->parent = new_tree_node;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+ int rc1 = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next, test_ast_node);
+ int rc2 = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next->next, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_gen_perm_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ int rc = 0;
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current_perm = NULL;
+ struct cil_tree_node *test_new_ast = NULL;
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ test_current_perm = test_tree->root->cl_head->cl_head->next->next->cl_head;
+
+ cil_tree_node_init(&test_new_ast);
+ test_new_ast->parent = test_ast_node;
+ test_new_ast->line = test_current_perm->line;
+
+ rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ int rc = 0;
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current_perm = NULL;
+ struct cil_tree_node *test_new_ast = NULL;
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_current_perm = NULL;
+
+ cil_tree_node_init(&test_new_ast);
+ test_new_ast->parent = test_ast_node;
+
+ rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_class *new_node;
+ cil_class_init(&new_node);
+
+ struct cil_tree_node *new_tree_node;
+ cil_tree_node_init(&new_tree_node);
+ new_tree_node->data = new_node;
+ new_tree_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_nodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ int rc = 0;
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_current_perm = NULL;
+ struct cil_tree_node *test_new_ast = NULL;
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_current_perm = test_tree->root->cl_head->cl_head->next->next->cl_head;
+
+ cil_tree_node_init(&test_new_ast);
+ test_new_ast->parent = test_ast_node;
+ test_new_ast->line = test_current_perm->line;
+
+ rc = cil_gen_perm(test_db, test_current_perm, test_new_ast);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_permset_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "(", "foo", ")", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_noperms_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_emptyperms_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_permset_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_permset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_perm_nodes(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_perm_nodes_failgen_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ cil_symtab_destroy(&test_cls->perms);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+ CuAssertIntEquals(tc, SEPOL_ENOMEM, rc);
+}
+
+void test_cil_gen_perm_nodes_inval_perm_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "(", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_perm_nodes(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node, CIL_PERM);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_permset *permset;
+ cil_permset_init(&permset);
+
+ int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_permset_sublist_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_permset *permset;
+ cil_permset_init(&permset);
+
+ int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset_startpermnull_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_permset *permset;
+ cil_permset_init(&permset);
+
+ int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_permset_permsetnull_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_permset *permset = NULL;
+
+ int rc = cil_fill_permset(test_tree->root->cl_head->cl_head->next->next->cl_head, permset);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_in_blockstrnull_neg(CuTest *tc) {
+ char *line[] = {"(", "in", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_in_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_in(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->cl_tail);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_CLASS);
+}
+
+void test_cil_gen_class_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_nodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_tree->root->cl_head->cl_head = NULL;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "test", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noclassname_neg(CuTest *tc) {
+ char *line[] = {"(", "class", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_namesublist_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_noperms(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_class_permsnotinlist_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "read", "write", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_extrapermlist_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", "(", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_class_listinlist_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "test", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_anonperms(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_classpermset_anonperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", "(", "extra", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_namedperms(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "perms", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_classpermset_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", "extra", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_emptypermslist_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_noperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_classnodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_classpermset_cpsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_classpermset *cps = NULL;
+
+ int rc = cil_fill_classpermset(test_tree->root->cl_head->cl_head->next->next->cl_head, cps);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classpermset_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "(", "foo", ")", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_noperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", "char", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_emptyperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classpermset_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classpermset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_classmap *map = NULL;
+ cil_classmap_init(&map);
+
+ test_ast_node->flavor = CIL_CLASSMAP;
+ test_ast_node->data = map;
+
+ struct cil_tree_node *test_ast_node_a;
+ cil_tree_node_init(&test_ast_node_a);
+
+ test_ast_node_a->parent = test_ast_node;
+ test_ast_node_a->line = test_tree->root->cl_head->cl_head->next->next->cl_head->line;
+ test_ast_node_a->path = test_tree->root->cl_head->cl_head->next->next->cl_head->path;
+
+ int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmap_perm_dupeperm_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_ast_node_a;
+ cil_tree_node_init(&test_ast_node_a);
+
+ test_ast_node_a->parent = test_ast_node;
+ test_ast_node_a->line = test_tree->root->cl_head->cl_head->next->next->cl_head->line;
+ test_ast_node_a->path = test_tree->root->cl_head->cl_head->next->next->cl_head->path;
+
+ int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+ CuAssertIntEquals(tc, SEPOL_EEXIST, rc);
+}
+
+void test_cil_gen_classmap_perm_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_ast_node_a;
+ cil_tree_node_init(&test_ast_node_a);
+
+ test_ast_node_a->parent = test_ast_node;
+ test_ast_node_a->line = test_tree->root->cl_head->cl_head->line;
+ test_ast_node_a->path = test_tree->root->cl_head->cl_head->path;
+
+ test_db = NULL;
+
+ int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_ast_node_a;
+ cil_tree_node_init(&test_ast_node_a);
+
+ test_ast_node_a->parent = test_ast_node;
+ test_ast_node_a->line = test_tree->root->cl_head->cl_head->line;
+ test_ast_node_a->path = test_tree->root->cl_head->cl_head->path;
+
+ int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_perm_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_ast_node_a = NULL;
+
+ int rc = cil_gen_classmap_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node_a);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmap_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_emptyperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmap_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classmap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_anonpermset(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read",
+ "(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmapping_anonpermset_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read",
+ "(", "file", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_namedpermset(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classmapping_noclassmapname_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_noclassmapperm_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_nopermissionsets_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read",
+ "(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classmapping_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read",
+ "(", "file", "(", "open", "read", "getattr", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classmapping(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_COMMON);
+}
+
+void test_cil_gen_common_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "common", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_twoperms_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "foo", "(", "write", ")", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_permsublist_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_common_noperms_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid(CuTest *tc) {
+ char *line[] = {"(", "sid", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_sid_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", "foo", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sid_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SIDCONTEXT);
+}
+
+void test_cil_gen_sidcontext_namedcontext(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "something", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SIDCONTEXT);
+}
+
+void test_cil_gen_sidcontext_halfcontext_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_empty_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_dblname_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "test2", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_pcurrnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sidcontext_astnodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, NULL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE);
+}
+
+void test_cil_gen_type_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", "bar," ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattribute(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "test", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPEATTRIBUTE);
+}
+
+void test_cil_gen_typeattribute_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_typeattribute_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_typeattribute_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattribute_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "foo", "bar," ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_typebounds_notype1_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_type1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "(", "type_a", ")", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_notype2_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_type2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", "(", "type_b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", "type_b", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typebounds_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_typebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_typepermissive_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_typeinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "(", "type_a", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "type_a", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typepermissive_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_typepermissive(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nametypetransition_strinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "(", "str", ")", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nostr_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_srcinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "(", "foo", ")", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nosrc_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_tgtinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "(", "bar", ")", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_notgt_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_classinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "(", "file", ")", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_destinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "(", "foobar", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_nodest_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_nametypetransition_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nametypetransition_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_nametypetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_namedtransition(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "namedtrans", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_low_l(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "(", "s0", "(", "c0", ")", ")", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_low_l_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "(", "s0", "(", ")", ")", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_anon_high_l(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_rangetransition_anon_high_l_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "(", "s0", "(", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nofirsttype_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_firsttype_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "(", "type_a_t", ")", "type_b_t", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nosecondtype_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_secondtype_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "(", "type_b_t", ")", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_class_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "(", "class", ")", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nolevel_l_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_nolevel_h_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rangetransition_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a_t", "type_b_t", "class", "(", "low_l", "high_l", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rangetransition(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_and(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_or(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "or", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_xor(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "xor", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_not(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "not", "foo", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_not_noexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "not", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_not_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "not", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_eq(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "eq", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_neq(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "neq", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_nested(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "or", "(","neq", "foo", "bar", ")", "(", "eq", "baz", "boo", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_expr_stack_nested_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "(","neq", "foo", "bar", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_nested_emptyargs_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "eq", "(", ")", "(", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_nested_missingoperator_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "or", "(","foo", "bar", ")", "(", "eq", "baz", "boo", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_arg1null_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "eq", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_arg2null_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "eq", "foo", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_extraarg_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "eq", "foo", "bar", "extra", ")",
+ "(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_booleanif *bif;
+ cil_boolif_init(&bif);
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, &bif->expr_stack);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_expr_stack_stacknull_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "xor", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_expr_stack(test_tree->root->cl_head->cl_head->next, CIL_BOOL, NULL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_true(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_false(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "false", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_multiplebools_unknowncond_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "dne", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_true(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_false(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "false", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_unknowncond_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "dne", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nested(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_nested_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "(", "or", "foo", "bar", ")", "baz", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "(", "or", "foo", "bar", ")", "baz", "beef", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_extra_parens_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "(", "or", "foo", "bar", ")", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nocond(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "baz",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_boolif_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "**", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_nocond_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_notruelist_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_boolif_empty_cond_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_true(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_false(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "false", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_multiplebools_unknowncond_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")",
+ "(", "dne", "(", "allow", "foo", "bar", "(", "write", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_true(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_false(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "false", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_unknowncond_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "dne", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_nocond(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "baz",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_nested(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_tunif_nested_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "(", "or", "foo", "bar", ")", "baz", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", "beef", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_extra_parens_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "(", "or", "foo", "bar", ")", ")",
+ "(", "true", "(", "allow", "foo", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "**", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true", "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_nocond_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_tunif_notruelist_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_tunif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_true(CuTest *tc) {
+ char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_condblock_false(CuTest *tc) {
+ char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_condblock_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDFALSE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_nocond_neg(CuTest *tc) {
+ char *line[] = {"(", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_condblock_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "read", ")", ")", "Extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_condblock(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_CONDTRUE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertStrEquals(tc, ((struct cil_typealias*)test_ast_node->data)->type_str, test_tree->root->cl_head->cl_head->next->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPEALIAS);
+}
+
+void test_cil_gen_typealias_incomplete_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_incomplete_neg2(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_extratype_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "foo", "extra_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typealias_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "test_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_and_two_types(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "and", "test_t", "test2_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_not(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "notypes_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_exclude_attr(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "attr", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+}
+
+void test_cil_gen_typeattributeset_exclude_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", "type_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "not", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "(", "filetypes", ")", "(", "test_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_emptylists_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_listinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "(", "test_t", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_typeattributeset_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "test_t", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_typeattributeset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userbounds(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_gen_userbounds_notype1_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_type1_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "(", "user1", ")", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_notype2_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_type2_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "(", "user2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "user2", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_userbounds_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_userbounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_role(CuTest *tc) {
+ char *line[] = {"(", "role", "test_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLE);
+}
+
+void test_cil_gen_role_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "test_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "test_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_extrarole_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "test_r", "extra_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_role_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "role", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLETRANSITION);
+}
+
+void test_cil_gen_roletransition_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletransition(NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_astnull_neg (CuTest *tc) {
+ char *line[] = {"(", "roletransition" "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_srcnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_tgtnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_resultnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletransition_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletransition(test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_true(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 1);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BOOL);
+}
+
+void test_cil_gen_bool_tunable_true(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_TUNABLE);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 1);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TUNABLE);
+}
+
+void test_cil_gen_bool_false(CuTest *tc) {
+ char *line[] = {"(", "boolean", "bar", "false", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 0);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_BOOL);
+}
+
+void test_cil_gen_bool_tunable_false(CuTest *tc) {
+ char *line[] = {"(", "tunable", "bar", "false", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_TUNABLE);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, ((struct cil_bool*)test_ast_node->data)->value, 0);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TUNABLE);
+}
+
+void test_cil_gen_bool_none_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_notbool_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_boolname_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_extraname_false_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "false", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_bool_extraname_true_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1type(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1t1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "t1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t2type(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t2", "type_t", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t2t2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t2", "t2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1role(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "role_r", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1r1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r2role(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r2", "role_r", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r2r2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r2", "r2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_t1t2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "t2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_r1r2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_r1r2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1u2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "u2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1user(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "user_u", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u1u1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "u1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u2user(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u2", "user_u", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_u2u2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u2", "u2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l2h2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1h1(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "h1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1h2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1l2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "l2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1h2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_h1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h1", "l1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg(CuTest *tc) {
+ char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_CONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg(CuTest *tc) {
+ char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_CONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "h2", "h1", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "neq", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", "neq", "l2", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_noexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_emptyparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_not_extraparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "not", "(", "neq", "l2", "h2", ")", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or",
+ "(", "neq", "l1", "l2", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or",
+ "(", "foo", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_noexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_or_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "or", "(", "foo", ")", "(", "foo", ")", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and",
+ "(", "neq", "l1", "l2", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and",
+ "(", "foo", ")", "(", "neq", "l1", "h1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_noexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_and_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "and", "(", "foo", ")", "(", "foo", ")", "(", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_dom_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dom", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_domby_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "domby", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l2", "h2", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "(", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l1", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "l1", "(", "h2", ")", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "incomp", "foo", "foo", "extra", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_stacknull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, NULL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_operatorinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "(", "eq", ")", "t1", "type_t", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expr_stack_incorrectcall_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *parse_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *cons;
+ cil_constrain_init(&cons);
+ cil_classpermset_init(&cons->classpermset);
+ cil_fill_classpermset(parse_current->next->cl_head, cons->classpermset);
+
+ int rc = cil_gen_expr_stack(parse_current->next->next->cl_head->next->next, CIL_MLSCONSTRAIN, &cons->expr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "staff_r", "sysadm_r", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertStrEquals(tc, ((struct cil_roleallow*)test_ast_node->data)->src_str, test_current->next->data);
+ CuAssertStrEquals(tc, ((struct cil_roleallow*)test_ast_node->data)->tgt_str, test_current->next->next->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_ROLEALLOW);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_roleallow_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_roleallow(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_srcnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_tgtnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roleallow_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "foo", "bar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roleallow(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_rolebounds(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_gen_rolebounds_norole1_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_role1_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "(", "role1", ")", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_norole2_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_role2_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "(", "role2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "role2", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_rolebounds_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_rolebounds(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+
+void test_cil_gen_avrule(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->src_str, test_current->next->data);
+ CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->tgt_str, test_current->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_avrule*)test_ast_node->data)->classpermset->class_str, test_current->next->next->next->cl_head->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_AVRULE);
+ CuAssertPtrNotNull(tc, ((struct cil_avrule*)test_ast_node->data)->classpermset->permset->perms_list_str);
+
+ struct cil_list_item *test_list = ((struct cil_avrule*)test_ast_node->data)->classpermset->permset->perms_list_str->head;
+ test_current = test_current->next->next->next->cl_head->next->cl_head;
+
+ while(test_list != NULL) {
+ CuAssertIntEquals(tc, test_list->flavor, CIL_AST_STR);
+ CuAssertStrEquals(tc, test_list->data, test_current->data );
+ test_list = test_list->next;
+ test_current = test_current->next;
+ }
+}
+
+void test_cil_gen_avrule_permset(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "permset", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_avrule_permset_anon(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_avrule_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "permset", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourceparens(CuTest *tc) {
+ char *line[] = {"(", "allow", "(", "test", ")", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourceemptyparen_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "(", ")", "bar", "file", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetparens(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "(", "foo", ")", "bar", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetemptyparen_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "bar", "(", ")", "file", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "bar", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_sourcedomainnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_targetdomainnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_objectclassnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_permsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "foo", "bar", "(", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_avrule_twolists_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "bar", "(", "write", ")", "(", "read", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ int rc = cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+ CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_transition_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_srcnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_tgtnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_objnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_resultnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_transition_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+ CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_change_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_srcnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_tgtnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_objnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_resultnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_change_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_CHANGE);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->src_str, test_tree->root->cl_head->cl_head->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->tgt_str, test_tree->root->cl_head->cl_head->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->obj_str, test_tree->root->cl_head->cl_head->next->next->next->data);
+ CuAssertStrEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->result_str, test_tree->root->cl_head->cl_head->next->next->next->next->data);
+ CuAssertIntEquals(tc, ((struct cil_type_rule*)test_ast_node->data)->rule_kind, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_TYPE_RULE);
+}
+
+void test_cil_gen_type_rule_member_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_type_rule(NULL, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_srcnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_tgtnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_objnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_resultnull_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ test_tree->root->cl_head->cl_head->next->next->next->next = NULL;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_type_rule_member_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_MEMBER);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user(CuTest *tc) {
+ char *line[] = {"(", "user", "sysadm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, CIL_USER, test_ast_node->flavor);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertPtrEquals(tc, test_ast_node, ((struct cil_symtab_datum*)test_ast_node->data)->node);
+ CuAssertStrEquals(tc, test_tree->root->cl_head->cl_head->next->data, ((struct cil_symtab_datum*)test_ast_node->data)->name);
+}
+
+void test_cil_gen_user_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "user", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "user", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_nouser_neg(CuTest *tc) {
+ char *line[] = {"(", "user", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_user_xsinfo_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "sysadm", "xsinfo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", "lvl_l", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userlevel_anon_level(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userlevel_anon_level_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", "(", "s0", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_usernull_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_userrange_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "(", "user", ")", "level", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_levelnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_levelrangeempty_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user_u", "level", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user", "level", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userlevel_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "user", "level", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_userlevel(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_named(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrange_anon(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrange_usernull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonuser_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "(", "user_u", ")", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_rangenamenull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonrangeinvalid_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", "(", "low", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_anonrangeempty_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user_u", "(", "low", "high", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrange_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "user", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_userrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_ast_node->data);
+ CuAssertIntEquals(tc, test_ast_node->flavor, CIL_SENS);
+
+}
+
+void test_cil_gen_sensitivity_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_sensitivity(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_sensnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_senslist_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "(", "s0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensitivity_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_sensalias_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_currnull_neg(CuTest *tc) {
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_sensalias(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init (&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_sensnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_senslist_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "(", "s0", "s1", ")", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_aliasnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_aliaslist_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "(", "alias", "alias2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_sensalias_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_category_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_category(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_catnull_neg(CuTest *tc){
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_catlist_neg(CuTest *tc){
+ char *line[] = {"(", "category", "(", "c0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_category_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catset_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_namenull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_setnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_namelist_neg(CuTest *tc) { //This should fail before gen_node call - additional syntax checks are needed
+ char *line[] = {"(", "categoryset", "(", "somecats", ")", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_notset_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "blah", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+// TODO: This doesn't actually test failure of gen_node
+void test_cil_gen_catset_nodefail_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", "(", "c3", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catset_settolistfail_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catset(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catalias_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catalias(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_catnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_aliasnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root->cl_head->cl_head->next->next = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catalias_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catrange_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_norange_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_emptyrange_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_extrarange_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, NULL, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catrange_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype(CuTest *tc) {
+ char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_roletype_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+void test_cil_gen_roletype_empty_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_rolelist_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", "(", "admin_r", ")", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+// TODO
+// Not sure this is actually testing roletype
+// I think this will just test that type is null
+void test_cil_gen_roletype_roletype_sublist_neg(CuTest *tc) {
+ char *line[] = {"(", "(", "roletype", "admin_r", ")", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_roletype_typelist_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", "admin_r", "(", "admin_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_roletype(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_userrole_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_empty_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_userlist_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", "(", "staff_u", ")", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+//TODO: see above
+void test_cil_gen_userrole_userrole_sublist_neg(CuTest *tc) {
+ char *line[] = {"(", "(", "userrole", "staff_u", ")", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_userrole_rolelist_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "(", "staff_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_classcommon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_missingclassname_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_noperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_classcommon_extraperms_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ int rc = cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_catorder_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db = NULL;
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_missingcats_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_nosublist_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "c0", "c255", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_catorder_nestedcat_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "(", "c255", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_dominance_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_nosensitivities_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_dominance_nosublist_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "s0", "s2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_senscat_nosublist(CuTest *tc) {
+ char *line[] = {"(", "sensitivitycategory", "s1", "c0", "c255", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_senscat_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_nosensitivities_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_sublist_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "(", "c255", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_senscat_nocat_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivitycategory", "s1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_senscat(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_level *test_level;
+ cil_level_init(&test_level);
+
+ int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_level_sensnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_level *test_level;
+ cil_level_init(&test_level);
+
+ int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next, test_level);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level_levelnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_level *test_level = NULL;
+
+ int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_level_nocat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_level *test_level;
+ cil_level_init(&test_level);
+
+ int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_level_emptycat_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_level *test_level;
+ cil_level_init(&test_level);
+
+ int rc = cil_fill_level(test_tree->root->cl_head->next->next->cl_head->next->next->cl_head, test_level);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_level_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "level", "(", "low", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_emptysensparens_neg(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", "s0", "(", "c0", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_emptycat_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_nosens_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_level_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_level(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_levelrange_rangeinvalid_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", "extra", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_namenull_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_rangenull_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_rangeempty_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_levelrange_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_levelrange(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_constrain_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "dne", "l1", "l2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_classset_noperm_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_noclass_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_permset_noperm_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_expression_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_constrain_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_context_unnamedlvl(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "(", "s0", ")", "(", "s0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_context_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context = NULL;
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nouser_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_norole_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_notype_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nolowlvl_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_nohighlvl_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "(", "low", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_unnamedlvl_nocontextlow_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "(", "s0", "(", ")", ")", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_context_unnamedlvl_nocontexthigh_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "type_t", "low", "(", "s0", "(", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_context *test_context;
+ cil_context_init(&test_context);
+
+ int rc = cil_fill_context(test_tree->root->cl_head->cl_head->next->next->cl_head, test_context);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_context_notinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_extralevel_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", "extra", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_emptycontext_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", "(", "extra", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_doubleparen_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "(", "system_u", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_norole_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_roleinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "(", "role_r", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_notype_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_typeinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "(", "type_t", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nolevels_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "type_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nosecondlevel_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "role_r", "type_t", "(", "low", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "context", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_nouser_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "s0", ")", "(", "s0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_context_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "system_u", "object_r", "node_lo_t", "(", "s0", ")", "(", "s0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_dir(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "dir", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_file(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_char(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "char", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_block(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "block", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_socket(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "socket", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_pipe(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "pipe", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_symlink(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "symlink", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_any(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "any", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "dne", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_filecon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str1null_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str1_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "(", "root", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str2null_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_str2_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "(", "path", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_classnull_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_class_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "(", "file", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_contextnull_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_filecon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "context", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_filecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_udp(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "80", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_tcp(CuTest *tc) {
+ char *line[] = {"(", "portcon", "tcp", "80", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_unknownprotocol_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "unknown", "80", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "80", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_portrange(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "25", "75", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_portcon_portrange_one_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "0", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_portrange_morethanone_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "0", "1", "2", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_singleport_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "foo", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_lowport_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "foo", "90", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_highport_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "80", "foo", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "0", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "(", "0", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_str1null_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_str1parens_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "(", "80", ")", "port", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_portnull_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_contextnull_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "port", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "80", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_portcon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "80", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_portcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_nodecon *nodecon;
+ cil_nodecon_init(&nodecon);
+ cil_ipaddr_init(&nodecon->addr);
+
+ int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_fill_ipaddr_addrnodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_nodecon *nodecon;
+ cil_nodecon_init(&nodecon);
+ cil_ipaddr_init(&nodecon->addr);
+
+ int rc = cil_fill_ipaddr(NULL, nodecon->addr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_addrnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_nodecon *nodecon;
+ cil_nodecon_init(&nodecon);
+ nodecon->addr = NULL;
+
+ int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_addrinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "(", "192.168.1.1", ")", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_nodecon *nodecon;
+ cil_nodecon_init(&nodecon);
+ cil_ipaddr_init(&nodecon->addr);
+
+ int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_fill_ipaddr_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", "extra", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_nodecon *nodecon;
+ cil_nodecon_init(&nodecon);
+ cil_ipaddr_init(&nodecon->addr);
+
+ int rc = cil_fill_ipaddr(test_tree->root->cl_head->cl_head->next->cl_head, nodecon->addr);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_ipnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_ipanon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_ipanon_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.1.1", ")", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_netmasknull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_netmaskanon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "(", "255.255.255.4", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_nodecon_netmaskanon_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "(", "str0", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_contextnull_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_nodecon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "(", "system_u", "object_r", "type_t", "(", "low", "high", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_genfscon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_genfscon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_typenull_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_typeparens_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "(", "type", ")", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_pathnull_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_pathparens_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "(", "path", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_contextnull_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "(", "system_u", "object_r", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_genfscon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_genfscon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_netifcon_nested(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_netifcon_nested_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "(", "eth1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_emptysecondlist_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_extra_nested_secondlist_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "extra",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_missingobjects_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_nested_secondnested_missingobjects_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_ethmissing_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_interfacemissing_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_netifcon_packetmissing_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_pirqcon_pirqnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "notint", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_nopirq_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_pirqrange_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "(", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_anoncontext_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "(", "con", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pirqcon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_pirqcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", "1", "2", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_firstnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", "foo", "2", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_secondnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", "1", "foo", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_empty_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_singleiomem_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "(", "1", "2", "3", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_iomemnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "notint", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_noiomem_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_anoncontext_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "(", "con", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_iomemcon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_iomemcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", "1", "2", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_firstnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", "foo", "2", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_secondnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", "1", "foo", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_empty_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_singleioport_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "(", "1", "2", "3", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_ioportnotint_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "notint", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_noioport_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_anoncontext_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "(", "con", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ioportcon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_ioportcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_pcidevicecon_pcidevicenotint_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "notint", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_nopcidevice_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_pcidevicerange_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "(", "1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_anoncontext_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "(", "con", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_pcidevicecon_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_pcidevicecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_anoncontext(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_anoncontext_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "(", "system_u", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_xattr(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_task(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "task", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_transition(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "trans", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_fsuse_invalidtype_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "foo", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_notype_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_typeinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "(", "xattr", ")", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_nofilesystem_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_filesysteminparens_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "(", "ext3", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_emptyconparens_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "con", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_fsuse_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_fsuse(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparams(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", ")", "(", "type", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_type(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_role(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "role", "a", ")", ")", "(", "role", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_user(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "user", "a", ")", ")", "(", "user", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_sensitivity(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")", "(", "sensitivity", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_category(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "category", "a", ")", ")", "(", "category", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_catset(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "categoryset", "a", ")", ")", "(", "categoryset", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_level(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "level", "a", ")", ")", "(", "level", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_class(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "class", "a", ")", ")", "(", "class", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_classmap(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "classmap", "a", ")", ")", "(", "classmap", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_permset(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")",
+ "(", "allow", "foo", "bar", "baz", "a", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_duplicate(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "class", "a",")", "(", "class", "x", ")", ")", "(", "class", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_macro_duplicate_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "class", "a",")", "(", "class", "a", ")", ")", "(", "class", "b", "(", "read," ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_unknown_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node = NULL;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_unnamed_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparam_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_nosecondparam_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "foo", "a", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_noparam_name_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_emptyparam_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", ")", ")", "(", "foo", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_macro_paramcontainsperiod_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a.", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_macro(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_noargs(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_anon(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_call_empty_call_neg(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_name_inparens_neg(CuTest *tc) {
+ char *line[] = {"(", "call", "(", "mm", ")", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_call_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "call", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_optional_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_unnamed_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", "(", "opt", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_optional_emptyoptional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_optional_norule_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap(CuTest *tc) {
+ char *line[] = {"(", "policycap", "open_perms", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_policycap_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", "(", "pol", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", "pol", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_policycap_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", "pol", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_policycap(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipv4(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ipaddr_ipv4_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", ".168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipv6(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_gen_ipaddr_ipv6_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "2001:0db8:85a3:0000:0000:8a2e:0370:::7334", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_noname_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_nameinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "(", "ip", ")", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_noip_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_ipinparens_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "(", "192.168.1.1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_extra_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db = NULL;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_currnull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_gen_ipaddr_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+/*
+ cil_build_ast test cases
+*/
+
+void test_cil_build_ast(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_dbnull_neg(CuTest *tc) {
+ char *line[] = {"(", "test", "\"qstring\"", ")", ";comment", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *null_db = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_build_ast(null_db, test_tree->root, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_astnull_neg(CuTest *tc) {
+ char *line[] = {"(", "test", "\"qstring\"", ")", ";comment", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_db->ast->root = NULL;
+
+ int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_suberr_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "test", "(", "block", "(", "type", "log", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_treenull_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "bar", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ test_tree->root = NULL;
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_db->ast->root = NULL;
+
+ int rc = cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_block(CuTest *tc) {
+ char *line[] = {"(", "block", "test", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_block_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_blockinherit(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_blockinherit_neg(CuTest *tc) {
+ char *line[] = {"(", "blockinherit", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_permset(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, CIL_TREE_SKIP_NEXT, finished);
+}
+
+void test_cil_build_ast_node_helper_permset_neg(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_in(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_in_neg(CuTest *tc) {
+ char *line[] = {"(", "in", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_class(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_class_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_classpermset(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", "(", "read", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, CIL_TREE_SKIP_NEXT, finished);
+}
+
+void test_cil_build_ast_node_helper_classpermset_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+
+}
+
+void test_cil_build_ast_node_helper_classmap(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_classmap_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_classmapping(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_classmapping_neg(CuTest *tc) {
+ char *line[] = {"(", "classmapping", "files", "read", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_common(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_common_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sid(CuTest *tc) {
+ char *line[] = {"(", "sid", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_sid_neg(CuTest *tc) {
+ char *line[] = {"(", "sid", "(", "blah", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah", "blah", "blah", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_sidcontext_neg(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "(", "blah", "blah", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_user(CuTest *tc) {
+ char *line[] = {"(", "user", "jimmypage", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_user_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo", "bar", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userlevel(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "johnpauljones", "level", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_userlevel_neg(CuTest *tc) {
+ char *line[] = {"(", "userlevel", "johnpauljones", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userrange(CuTest *tc) {
+ char *line[] = {"(", "userrange", "johnpauljones", "range", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_userrange_neg(CuTest *tc) {
+ char *line[] = {"(", "userrange", "johnpauljones", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_neg(CuTest *tc) {
+ char *line[] = {"(", "type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_attribute(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_attribute_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typebounds(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "foo", "bar", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typebounds_neg(CuTest *tc) {
+ char *line[] = {"(", "typebounds", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typepermissive(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", "foo", ")", NULL};
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typepermissive_neg(CuTest *tc) {
+ char *line[] = {"(", "typepermissive", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_nametypetransition(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_nametypetransition_neg(CuTest *tc) {
+ char *line[] = {"(", "nametypetransition", "str", "foo", "bar", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_rangetransition(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", "type_a", "type_b", "class", "(", "low_l", "high_l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_rangetransition_neg(CuTest *tc) {
+ char *line[] = {"(", "rangetransition", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_boolif(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_boolif_neg(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "*&", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_true(CuTest *tc) {
+ char *line[] = {"(", "true", "(", "allow", "foo", "bar", "baz", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_true_neg(CuTest *tc) {
+ char *line[] = {"(", "true", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_false(CuTest *tc) {
+ char *line[] = {"(", "false", "(", "allow", "foo", "bar", "baz", "(", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_condblock_false_neg(CuTest *tc) {
+ char *line[] = {"(", "false", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_tunif(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_tunif_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "*&", "foo", "bar", ")",
+ "(", "allow", "foo", "bar", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typealias(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typealias_notype_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattribute(CuTest *tc)
+{
+ char *line[] = {"(", "typeattribute", "type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattribute_neg(CuTest *tc)
+{
+ char *line[] = {"(", "typeattribute", ".fail.type", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattributeset(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "filetypes", "(", "and", "test_t", "test2_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_typeattributeset_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattributeset", "files", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userbounds(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_userbounds_neg(CuTest *tc) {
+ char *line[] = {"(", "userbounds", "user1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_role(CuTest *tc) {
+ char *line[] = {"(", "role", "test_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_role_neg(CuTest *tc) {
+ char *line[] = {"(", "role", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletransition(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletransition_neg(CuTest *tc) {
+ char *line[] = {"(", "roletransition", "foo_r", "bar_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roleallow(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "staff_r", "sysadm_r", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roleallow_neg(CuTest *tc) {
+ char *line[] = {"(", "roleallow", "staff_r", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_rolebounds(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_rolebounds_neg(CuTest *tc) {
+ char *line[] = {"(", "rolebounds", "role1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_allow(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_allow_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_auditallow(CuTest *tc) {
+ char *line[] = {"(", "auditallow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_auditallow_neg(CuTest *tc) {
+ char *line[] = {"(", "auditallow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_dontaudit(CuTest *tc) {
+ char *line[] = {"(", "dontaudit", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_dontaudit_neg(CuTest *tc) {
+ char *line[] = {"(", "dontaudit", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_neverallow(CuTest *tc) {
+ char *line[] = {"(", "neverallow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_avrule_neverallow_neg(CuTest *tc) {
+ char *line[] = {"(", "neverallow", "foo", "bar", "(", "read", "write", ")", "blah", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_transition(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_transition_neg(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_change(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_change_neg(CuTest *tc) {
+ char *line[] = {"(", "typechange", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_member(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_type_rule_member_neg(CuTest *tc) {
+ char *line[] = {"(", "typemember", "foo", "bar", "file", "foobar", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_tunable(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_bool_tunable_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensitivity(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensitivity_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_sensalias_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_category(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_category_neg(CuTest *tc) {
+ char *line[] = {"(", "category", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catset(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_catset_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catorder(CuTest *tc) {
+ char *line[] = {"(", "categoryorder", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_catorder_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryorder", "c0", "c1", "c2", "extra", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catalias(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catalias_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "range", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_catrange(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", "range", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 1, finished);
+}
+
+void test_cil_build_ast_node_helper_catrange_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryrange", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_build_ast_node_helper_roletype(CuTest *tc) {
+ char *line[] = {"(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_roletype_neg(CuTest *tc) {
+ char *line[] = {"(", "roletype", "(", "admin_r", ")", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_userrole(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_userrole_neg(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "(", "staff_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_classcommon(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "foo", "foo", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_classcommon_neg(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "staff_u", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_dominance_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->next->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_senscat_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->next->next->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_level(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_level_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "low", "(", "s0", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->next->next->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_levelrange(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_levelrange_neg(CuTest *tc) {
+ char *line[] = {"(", "levelrange", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_constrain(CuTest *tc) {
+ char *line[] = {"(", "constrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_constrain_neg(CuTest *tc) {
+ char *line[] = {"(", "constrain", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_mlsconstrain(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_mlsconstrain_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_context(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", "node_lo_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_context_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "localhost_node_label", "(", "system_u", "object_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_filecon(CuTest *tc) {
+ char *line[] = {"(", "filecon", "root", "path", "file", "context", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_filecon_neg(CuTest *tc) {
+ char *line[] = {"(", "filecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_portcon(CuTest *tc) {
+ char *line[] = {"(", "portcon", "udp", "25", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_portcon_neg(CuTest *tc) {
+ char *line[] = {"(", "portcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_nodecon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_nodecon_neg(CuTest *tc) {
+ char *line[] = {"(", "nodecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_genfscon(CuTest *tc) {
+ char *line[] = {"(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_genfscon_neg(CuTest *tc) {
+ char *line[] = {"(", "genfscon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_netifcon(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_netifcon_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pirqcon(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pirqcon_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_iomemcon(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_iomemcon_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ioportcon(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ioportcon_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_fsuse(CuTest *tc) {
+ char *line[] = {"(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_fsuse_neg(CuTest *tc) {
+ char *line[] = {"(", "fsuse", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_nested_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")", "(", "type", "b", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_macro *macro;
+ cil_macro_init(¯o);
+
+ struct cil_tree_node *macronode;
+ cil_tree_node_init(¯onode);
+ macronode->data = macro;
+ macronode->flavor = CIL_MACRO;
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, macronode, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+ cil_db_destroy(&test_db);
+ cil_destroy_macro(macro);
+}
+
+void test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg(CuTest *tc) {
+ char *line[] = {"(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "allow", "foo", "bar", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_macro *macro;
+ cil_macro_init(¯o);
+
+ struct cil_tree_node *macronode;
+ cil_tree_node_init(¯onode);
+ macronode->data = macro;
+ macronode->flavor = CIL_MACRO;
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, macronode, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+
+ cil_db_destroy(&test_db);
+ cil_destroy_macro(macro);
+}
+
+void test_cil_build_ast_node_helper_gen_call(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_call_neg(CuTest *tc) {
+ char *line[] = {"(", "call", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_optional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_optional_neg(CuTest *tc) {
+ char *line[] = {"(", "optional", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_policycap(CuTest *tc) {
+ char *line[] = {"(", "policycap", "open_perms", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 1);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_policycap_neg(CuTest *tc) {
+ char *line[] = {"(", "policycap", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_node_helper_gen_ipaddr_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_node_helper_extraargsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_args_build *extra_args = NULL;
+
+ uint32_t finished = 0;
+
+ int rc = __cil_build_ast_node_helper(test_tree->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_build_ast_last_child_helper(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_args_build *extra_args = gen_build_args(test_db->ast->root, test_db, NULL, NULL);
+
+ int rc = __cil_build_ast_last_child_helper(test_tree->root->cl_head->cl_head, extra_args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_build_ast_last_child_helper_extraargsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ int rc = __cil_build_ast_last_child_helper(test_tree->root->cl_head->cl_head, NULL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_build_ast.h b/libsepol/cil/test/unit/test_cil_build_ast.h
new file mode 100644
index 0000000..d697433
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_build_ast.h
@@ -0,0 +1,1198 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_BUILD_AST_H_
+#define TEST_CIL_BUILD_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_parse_to_list(CuTest *);
+void test_cil_parse_to_list_currnull_neg(CuTest *);
+void test_cil_parse_to_list_listnull_neg(CuTest *);
+
+void test_cil_set_to_list(CuTest *);
+void test_cil_set_to_list_tree_node_null_neg(CuTest *);
+void test_cil_set_to_list_cl_head_null_neg(CuTest *);
+void test_cil_set_to_list_listnull_neg(CuTest *);
+
+void test_cil_gen_block(CuTest *);
+void test_cil_gen_block_justblock_neg(CuTest *);
+void test_cil_gen_block_noname_neg(CuTest *);
+void test_cil_gen_block_dbnull_neg(CuTest *);
+void test_cil_gen_block_treenull_neg(CuTest *);
+void test_cil_gen_block_nodenull_neg(CuTest *);
+void test_cil_gen_block_nodeparentnull_neg(CuTest *);
+void test_cil_destroy_block(CuTest *);
+
+void test_cil_gen_blockinherit(CuTest *);
+void test_cil_gen_blockinherit_namelist_neg(CuTest *);
+void test_cil_gen_blockinherit_namenull_neg(CuTest *);
+void test_cil_gen_blockinherit_extra_neg(CuTest *);
+void test_cil_gen_blockinherit_dbnull_neg(CuTest *);
+void test_cil_gen_blockinherit_currnull_neg(CuTest *);
+void test_cil_gen_blockinherit_astnull_neg(CuTest *);
+
+void test_cil_gen_perm(CuTest *);
+void test_cil_gen_perm_noname_neg(CuTest *);
+void test_cil_gen_perm_dbnull_neg(CuTest *);
+void test_cil_gen_perm_currnull_neg(CuTest *);
+void test_cil_gen_perm_astnull_neg(CuTest *);
+void test_cil_gen_perm_nodenull_neg(CuTest *);
+
+void test_cil_gen_permset(CuTest *);
+void test_cil_gen_permset_noname_neg(CuTest *);
+void test_cil_gen_permset_nameinparens_neg(CuTest *);
+void test_cil_gen_permset_noperms_neg(CuTest *);
+void test_cil_gen_permset_emptyperms_neg(CuTest *);
+void test_cil_gen_permset_extra_neg(CuTest *);
+void test_cil_gen_permset_dbnull_neg(CuTest *);
+void test_cil_gen_permset_currnull_neg(CuTest *);
+void test_cil_gen_permset_astnull_neg(CuTest *);
+
+void test_cil_gen_perm_nodes(CuTest *);
+void test_cil_gen_perm_nodes_failgen_neg(CuTest *);
+void test_cil_gen_perm_nodes_inval_perm_neg(CuTest *);
+
+void test_cil_fill_permset(CuTest *);
+void test_cil_fill_permset_sublist_neg(CuTest *);
+void test_cil_fill_permset_startpermnull_neg(CuTest *);
+void test_cil_fill_permset_permsetnull_neg(CuTest *);
+
+void test_cil_gen_in(CuTest *);
+void test_cil_gen_in_blockstrnull_neg(CuTest *);
+void test_cil_gen_in_extra_neg(CuTest *);
+void test_cil_gen_in_dbnull_neg(CuTest *);
+void test_cil_gen_in_currnull_neg(CuTest *);
+void test_cil_gen_in_astnull_neg(CuTest *);
+
+void test_cil_gen_class(CuTest *);
+void test_cil_gen_class_noname_neg(CuTest *);
+void test_cil_gen_class_nodenull_neg(CuTest *);
+void test_cil_gen_class_dbnull_neg(CuTest *);
+void test_cil_gen_class_currnull_neg(CuTest *);
+void test_cil_gen_class_noclass_neg(CuTest *);
+void test_cil_gen_class_noclassname_neg(CuTest *);
+void test_cil_gen_class_namesublist_neg(CuTest *);
+void test_cil_gen_class_noperms(CuTest *);
+void test_cil_gen_class_permsnotinlist_neg(CuTest *);
+void test_cil_gen_class_extrapermlist_neg(CuTest *);
+void test_cil_gen_class_listinlist_neg(CuTest *);
+
+void test_cil_fill_classpermset_anonperms(CuTest *);
+void test_cil_fill_classpermset_anonperms_neg(CuTest *);
+void test_cil_fill_classpermset_namedperms(CuTest *);
+void test_cil_fill_classpermset_extra_neg(CuTest *);
+void test_cil_fill_classpermset_emptypermslist_neg(CuTest *);
+void test_cil_fill_classpermset_noperms_neg(CuTest *);
+void test_cil_fill_classpermset_noclass_neg(CuTest *);
+void test_cil_fill_classpermset_classnodenull_neg(CuTest *);
+void test_cil_fill_classpermset_cpsnull_neg(CuTest *);
+
+void test_cil_gen_classpermset(CuTest *);
+void test_cil_gen_classpermset_noname_neg(CuTest *);
+void test_cil_gen_classpermset_nameinparens_neg(CuTest *);
+void test_cil_gen_classpermset_noclass_neg(CuTest *);
+void test_cil_gen_classpermset_noperms_neg(CuTest *);
+void test_cil_gen_classpermset_emptyperms_neg(CuTest *);
+void test_cil_gen_classpermset_extra_neg(CuTest *);
+void test_cil_gen_classpermset_dbnull_neg(CuTest *);
+void test_cil_gen_classpermset_currnull_neg(CuTest *);
+void test_cil_gen_classpermset_astnull_neg(CuTest *);
+
+void test_cil_gen_classmap_perm(CuTest *);
+void test_cil_gen_classmap_perm_dupeperm_neg(CuTest *);
+void test_cil_gen_classmap_perm_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmap_perm_currnull_neg(CuTest *tc);
+void test_cil_gen_classmap_perm_astnull_neg(CuTest *tc);
+
+void test_cil_gen_classmap(CuTest *);
+void test_cil_gen_classmap_extra_neg(CuTest *);
+void test_cil_gen_classmap_noname_neg(CuTest *);
+void test_cil_gen_classmap_emptyperms_neg(CuTest *);
+void test_cil_gen_classmap_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmap_currnull_neg(CuTest *tc);
+void test_cil_gen_classmap_astnull_neg(CuTest *tc);
+
+void test_cil_gen_classmapping_anonpermset(CuTest *);
+void test_cil_gen_classmapping_anonpermset_neg(CuTest *);
+void test_cil_gen_classmapping_namedpermset(CuTest *);
+void test_cil_gen_classmapping_noclassmapname_neg(CuTest *);
+void test_cil_gen_classmapping_noclassmapperm_neg(CuTest *);
+void test_cil_gen_classmapping_nopermissionsets_neg(CuTest *);
+void test_cil_gen_classmapping_emptyperms_neg(CuTest *);
+void test_cil_gen_classmapping_dbnull_neg(CuTest *tc);
+void test_cil_gen_classmapping_currnull_neg(CuTest *tc);
+void test_cil_gen_classmapping_astnull_neg(CuTest *tc);
+
+void test_cil_gen_common(CuTest *);
+void test_cil_gen_common_dbnull_neg(CuTest *tc);
+void test_cil_gen_common_currnull_neg(CuTest *tc);
+void test_cil_gen_common_astnull_neg(CuTest *tc);
+void test_cil_gen_common_noname_neg(CuTest *tc);
+void test_cil_gen_common_twoperms_neg(CuTest *tc);
+void test_cil_gen_common_permsublist_neg(CuTest *tc);
+void test_cil_gen_common_noperms_neg(CuTest *tc);
+
+void test_cil_gen_sid(CuTest *);
+void test_cil_gen_sid_noname_neg(CuTest *);
+void test_cil_gen_sid_nameinparens_neg(CuTest *);
+void test_cil_gen_sid_extra_neg(CuTest *);
+void test_cil_gen_sid_dbnull_neg(CuTest *);
+void test_cil_gen_sid_currnull_neg(CuTest *);
+void test_cil_gen_sid_astnull_neg(CuTest *);
+
+void test_cil_gen_sidcontext(CuTest *);
+void test_cil_gen_sidcontext_namedcontext(CuTest *);
+void test_cil_gen_sidcontext_halfcontext_neg(CuTest *);
+void test_cil_gen_sidcontext_noname_neg(CuTest *);
+void test_cil_gen_sidcontext_empty_neg(CuTest *);
+void test_cil_gen_sidcontext_nocontext_neg(CuTest *);
+void test_cil_gen_sidcontext_dblname_neg(CuTest *);
+void test_cil_gen_sidcontext_dbnull_neg(CuTest *);
+void test_cil_gen_sidcontext_pcurrnull_neg(CuTest *);
+void test_cil_gen_sidcontext_astnodenull_neg(CuTest *);
+
+void test_cil_gen_type(CuTest *);
+void test_cil_gen_type_neg(CuTest *);
+void test_cil_gen_type_dbnull_neg(CuTest *tc);
+void test_cil_gen_type_currnull_neg(CuTest *tc);
+void test_cil_gen_type_astnull_neg(CuTest *tc);
+void test_cil_gen_type_extra_neg(CuTest *tc);
+
+void test_cil_gen_typeattribute(CuTest *);
+void test_cil_gen_typeattribute_dbnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_currnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_astnull_neg(CuTest *tc);
+void test_cil_gen_typeattribute_extra_neg(CuTest *tc);
+
+void test_cil_gen_typeattr(CuTest *);
+void test_cil_gen_typeattr_dbnull_neg(CuTest *);
+void test_cil_gen_typeattr_currnull_neg(CuTest *);
+void test_cil_gen_typeattr_astnull_neg(CuTest *);
+void test_cil_gen_typeattr_typenull_neg(CuTest *);
+void test_cil_gen_typeattr_attrnull_neg(CuTest *);
+void test_cil_gen_typeattr_attrlist_neg(CuTest *);
+void test_cil_gen_typeattr_extra_neg(CuTest *);
+
+void test_cil_gen_typebounds(CuTest *);
+void test_cil_gen_typebounds_notype1_neg(CuTest *);
+void test_cil_gen_typebounds_type1inparens_neg(CuTest *);
+void test_cil_gen_typebounds_notype2_neg(CuTest *);
+void test_cil_gen_typebounds_type2inparens_neg(CuTest *);
+void test_cil_gen_typebounds_extra_neg(CuTest *);
+void test_cil_gen_typebounds_dbnull_neg(CuTest *);
+void test_cil_gen_typebounds_currnull_neg(CuTest *);
+void test_cil_gen_typebounds_astnull_neg(CuTest *);
+
+void test_cil_gen_typepermissive(CuTest *);
+void test_cil_gen_typepermissive_noname_neg(CuTest *);
+void test_cil_gen_typepermissive_typeinparens_neg(CuTest *);
+void test_cil_gen_typepermissive_extra_neg(CuTest *);
+void test_cil_gen_typepermissive_dbnull_neg(CuTest *);
+void test_cil_gen_typepermissive_currnull_neg(CuTest *);
+void test_cil_gen_typepermissive_astnull_neg(CuTest *);
+
+void test_cil_gen_nametypetransition(CuTest *);
+void test_cil_gen_nametypetransition_nostr_neg(CuTest *);
+void test_cil_gen_nametypetransition_strinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_nosrc_neg(CuTest *);
+void test_cil_gen_nametypetransition_srcinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_notgt_neg(CuTest *);
+void test_cil_gen_nametypetransition_tgtinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_noclass_neg(CuTest *);
+void test_cil_gen_nametypetransition_classinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_nodest_neg(CuTest *);
+void test_cil_gen_nametypetransition_destinparens_neg(CuTest *);
+void test_cil_gen_nametypetransition_extra_neg(CuTest *);
+void test_cil_gen_nametypetransition_dbnull_neg(CuTest *);
+void test_cil_gen_nametypetransition_currnull_neg(CuTest *);
+void test_cil_gen_nametypetransition_astnull_neg(CuTest *);
+
+void test_cil_gen_rangetransition(CuTest *);
+void test_cil_gen_rangetransition_namedtransition(CuTest *);
+void test_cil_gen_rangetransition_anon_low_l(CuTest *);
+void test_cil_gen_rangetransition_anon_low_l_neg(CuTest *);
+void test_cil_gen_rangetransition_anon_high_l(CuTest *);
+void test_cil_gen_rangetransition_anon_high_l_neg(CuTest *);
+void test_cil_gen_rangetransition_dbnull_neg(CuTest *);
+void test_cil_gen_rangetransition_currnull_neg(CuTest *);
+void test_cil_gen_rangetransition_astnull_neg(CuTest *);
+void test_cil_gen_rangetransition_nofirsttype_neg(CuTest *);
+void test_cil_gen_rangetransition_firsttype_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_nosecondtype_neg(CuTest *);
+void test_cil_gen_rangetransition_secondtype_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_noclass_neg(CuTest *);
+void test_cil_gen_rangetransition_class_inparens_neg(CuTest *);
+void test_cil_gen_rangetransition_nolevel_l_neg(CuTest *);
+void test_cil_gen_rangetransition_nolevel_h_neg(CuTest *);
+void test_cil_gen_rangetransition_extra_neg(CuTest *);
+
+void test_cil_gen_expr_stack_and(CuTest *);
+void test_cil_gen_expr_stack_or(CuTest *);
+void test_cil_gen_expr_stack_xor(CuTest *);
+void test_cil_gen_expr_stack_not(CuTest *);
+void test_cil_gen_expr_stack_not_noexpr_neg(CuTest *);
+void test_cil_gen_expr_stack_not_extraexpr_neg(CuTest *);
+void test_cil_gen_expr_stack_eq(CuTest *);
+void test_cil_gen_expr_stack_neq(CuTest *);
+void test_cil_gen_expr_stack_nested(CuTest *);
+void test_cil_gen_expr_stack_nested_neg(CuTest *);
+void test_cil_gen_expr_stack_nested_emptyargs_neg(CuTest *);
+void test_cil_gen_expr_stack_nested_missingoperator_neg(CuTest *);
+void test_cil_gen_expr_stack_arg1null_neg(CuTest *);
+void test_cil_gen_expr_stack_arg2null_neg(CuTest *);
+void test_cil_gen_expr_stack_extraarg_neg(CuTest *);
+void test_cil_gen_expr_stack_currnull_neg(CuTest *);
+void test_cil_gen_expr_stack_stacknull_neg(CuTest *);
+
+void test_cil_gen_boolif_multiplebools_true(CuTest *);
+void test_cil_gen_boolif_multiplebools_false(CuTest *);
+void test_cil_gen_boolif_multiplebools_unknowncond_neg(CuTest *);
+void test_cil_gen_boolif_true(CuTest *);
+void test_cil_gen_boolif_false(CuTest *);
+void test_cil_gen_boolif_unknowncond_neg(CuTest *);
+void test_cil_gen_boolif_nested(CuTest *);
+void test_cil_gen_boolif_nested_neg(CuTest *);
+void test_cil_gen_boolif_extra_neg(CuTest *);
+void test_cil_gen_boolif_extra_parens_neg(CuTest *);
+void test_cil_gen_boolif_nocond(CuTest *);
+void test_cil_gen_boolif_neg(CuTest *);
+void test_cil_gen_boolif_dbnull_neg(CuTest *);
+void test_cil_gen_boolif_currnull_neg(CuTest *);
+void test_cil_gen_boolif_astnull_neg(CuTest *);
+void test_cil_gen_boolif_nocond_neg(CuTest *);
+void test_cil_gen_boolif_notruelist_neg(CuTest *);
+void test_cil_gen_boolif_empty_cond_neg(CuTest *);
+
+void test_cil_gen_else(CuTest *);
+void test_cil_gen_else_neg(CuTest *);
+void test_cil_gen_else_dbnull_neg(CuTest *);
+void test_cil_gen_else_currnull_neg(CuTest *);
+void test_cil_gen_else_astnull_neg(CuTest *);
+
+void test_cil_gen_tunif_multiplebools_true(CuTest *);
+void test_cil_gen_tunif_multiplebools_false(CuTest *);
+void test_cil_gen_tunif_multiplebools_unknowncond_neg(CuTest *);
+void test_cil_gen_tunif_true(CuTest *);
+void test_cil_gen_tunif_false(CuTest *);
+void test_cil_gen_tunif_unknowncond_neg(CuTest *);
+void test_cil_gen_tunif_nocond(CuTest *);
+void test_cil_gen_tunif_nested(CuTest *);
+void test_cil_gen_tunif_nested_neg(CuTest *);
+void test_cil_gen_tunif_extra_neg(CuTest *);
+void test_cil_gen_tunif_extra_parens_neg(CuTest *);
+void test_cil_gen_tunif_neg(CuTest *);
+void test_cil_gen_tunif_dbnull_neg(CuTest *);
+void test_cil_gen_tunif_currnull_neg(CuTest *);
+void test_cil_gen_tunif_astnull_neg(CuTest *);
+void test_cil_gen_tunif_nocond_neg(CuTest *);
+void test_cil_gen_tunif_notruelist_neg(CuTest *);
+
+void test_cil_gen_condblock_true(CuTest *);
+void test_cil_gen_condblock_false(CuTest *);
+void test_cil_gen_condblock_dbnull_neg(CuTest *);
+void test_cil_gen_condblock_currnull_neg(CuTest *);
+void test_cil_gen_condblock_astnull_neg(CuTest *);
+void test_cil_gen_condblock_nocond_neg(CuTest *);
+void test_cil_gen_condblock_extra_neg(CuTest *);
+
+void test_cil_gen_typealias(CuTest *);
+void test_cil_gen_typealias_incomplete_neg(CuTest *);
+void test_cil_gen_typealias_incomplete_neg2(CuTest *);
+void test_cil_gen_typealias_extratype_neg(CuTest *);
+void test_cil_gen_typealias_dbnull_neg(CuTest *tc);
+void test_cil_gen_typealias_currnull_neg(CuTest *tc);
+void test_cil_gen_typealias_astnull_neg(CuTest *tc);
+
+void test_cil_gen_typeattributeset(CuTest *);
+void test_cil_gen_typeattributeset_and_two_types(CuTest *);
+void test_cil_gen_typeattributeset_not(CuTest *);
+void test_cil_gen_typeattributeset_exclude_attr(CuTest *);
+void test_cil_gen_typeattributeset_exclude_neg(CuTest *);
+void test_cil_gen_typeattributeset_dbnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_currnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_astnull_neg(CuTest *);
+void test_cil_gen_typeattributeset_noname_neg(CuTest *);
+void test_cil_gen_typeattributeset_nameinparens_neg(CuTest *);
+void test_cil_gen_typeattributeset_emptylists_neg(CuTest *);
+void test_cil_gen_typeattributeset_listinparens_neg(CuTest *);
+void test_cil_gen_typeattributeset_extra_neg(CuTest *);
+
+void test_cil_gen_userbounds(CuTest *);
+void test_cil_gen_userbounds_notype1_neg(CuTest *);
+void test_cil_gen_userbounds_type1_inparens_neg(CuTest *);
+void test_cil_gen_userbounds_notype2_neg(CuTest *);
+void test_cil_gen_userbounds_type2_inparens_neg(CuTest *);
+void test_cil_gen_userbounds_extra_neg(CuTest *);
+void test_cil_gen_userbounds_dbnull_neg(CuTest *);
+void test_cil_gen_userbounds_currnull_neg(CuTest *);
+void test_cil_gen_userbounds_astnull_neg(CuTest *);
+
+void test_cil_gen_role(CuTest *);
+void test_cil_gen_role_dbnull_neg(CuTest *tc);
+void test_cil_gen_role_currnull_neg(CuTest *tc);
+void test_cil_gen_role_astnull_neg(CuTest *tc);
+void test_cil_gen_role_extrarole_neg(CuTest *tc);
+void test_cil_gen_role_noname_neg(CuTest *tc);
+
+void test_cil_gen_roletransition(CuTest *);
+void test_cil_gen_roletransition_currnull_neg(CuTest *);
+void test_cil_gen_roletransition_astnull_neg(CuTest *);
+void test_cil_gen_roletransition_srcnull_neg(CuTest *);
+void test_cil_gen_roletransition_tgtnull_neg(CuTest *);
+void test_cil_gen_roletransition_resultnull_neg(CuTest *);
+void test_cil_gen_roletransition_extra_neg(CuTest *);
+
+void test_cil_gen_bool_true(CuTest *);
+void test_cil_gen_bool_tunable_true(CuTest *);
+void test_cil_gen_bool_false(CuTest *);
+void test_cil_gen_bool_tunable_false(CuTest *);
+void test_cil_gen_bool_none_neg(CuTest *);
+void test_cil_gen_bool_dbnull_neg(CuTest *);
+void test_cil_gen_bool_currnull_neg(CuTest *);
+void test_cil_gen_bool_astnull_neg(CuTest *);
+void test_cil_gen_bool_notbool_neg(CuTest *);
+void test_cil_gen_bool_boolname_neg(CuTest *);
+void test_cil_gen_bool_extraname_false_neg(CuTest *);
+void test_cil_gen_bool_extraname_true_neg(CuTest *);
+
+void test_cil_gen_constrain_expr_stack_eq2_t1type(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t1t1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t2type(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t2t2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1role(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1r1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r2role(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r2r2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_t1t2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_r1r2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_r1r2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1u2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1user(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u1u1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u2user(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_u2u2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l2h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1h1(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1l2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1h2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_h1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_l1l2_constrain_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_l1l2_constrain_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_leftkeyword_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_eq2_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_noteq_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_emptyparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_not_extraparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_emptyfirstparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_missingsecondexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_emptysecondparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_or_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_noexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_emptyfirstparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_missingsecondexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_emptysecondparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_and_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_dom_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_domby_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_noexpr1_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_expr1inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_noexpr2_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_expr2inparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incomp_extraexpr_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_currnull_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_stacknull_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_operatorinparens_neg(CuTest *);
+void test_cil_gen_constrain_expr_stack_incorrectcall_neg(CuTest *);
+
+void test_cil_gen_roleallow(CuTest *);
+void test_cil_gen_roleallow_dbnull_neg(CuTest *);
+void test_cil_gen_roleallow_currnull_neg(CuTest *);
+void test_cil_gen_roleallow_astnull_neg(CuTest *);
+void test_cil_gen_roleallow_srcnull_neg(CuTest *);
+void test_cil_gen_roleallow_tgtnull_neg(CuTest *);
+void test_cil_gen_roleallow_extra_neg(CuTest *);
+
+void test_cil_gen_rolebounds(CuTest *);
+void test_cil_gen_rolebounds_norole1_neg(CuTest *);
+void test_cil_gen_rolebounds_role1_inparens_neg(CuTest *);
+void test_cil_gen_rolebounds_norole2_neg(CuTest *);
+void test_cil_gen_rolebounds_role2_inparens_neg(CuTest *);
+void test_cil_gen_rolebounds_extra_neg(CuTest *);
+void test_cil_gen_rolebounds_dbnull_neg(CuTest *);
+void test_cil_gen_rolebounds_currnull_neg(CuTest *);
+void test_cil_gen_rolebounds_astnull_neg(CuTest *);
+
+void test_cil_gen_avrule(CuTest *);
+void test_cil_gen_avrule_permset(CuTest *);
+void test_cil_gen_avrule_permset_anon(CuTest *);
+void test_cil_gen_avrule_extra_neg(CuTest *);
+void test_cil_gen_avrule_sourceparens(CuTest *);
+void test_cil_gen_avrule_sourceemptyparen_neg(CuTest *);
+void test_cil_gen_avrule_targetparens(CuTest *);
+void test_cil_gen_avrule_targetemptyparen_neg(CuTest *);
+void test_cil_gen_avrule_currnull_neg(CuTest *tc);
+void test_cil_gen_avrule_astnull_neg(CuTest *tc);
+void test_cil_gen_avrule_sourcedomainnull_neg(CuTest *tc);
+void test_cil_gen_avrule_targetdomainnull_neg(CuTest *tc);
+void test_cil_gen_avrule_objectclassnull_neg(CuTest *tc);
+void test_cil_gen_avrule_permsnull_neg(CuTest *tc);
+void test_cil_gen_avrule_twolists_neg(CuTest *);
+//TODO: add cases to cover parse_current->next->cl_head != NULL || parse_current->next->next->cl_head != NULL
+// || parse_current->next->next->next->cl_head != NULL
+
+void test_cil_gen_type_rule_transition(CuTest *);
+void test_cil_gen_type_rule_transition_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_transition_extra_neg(CuTest *);
+
+void test_cil_gen_type_rule_change(CuTest *);
+void test_cil_gen_type_rule_change_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_change_extra_neg(CuTest *);
+
+void test_cil_gen_type_rule_member(CuTest *);
+void test_cil_gen_type_rule_member_currnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_astnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_srcnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_tgtnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_objnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_resultnull_neg(CuTest *);
+void test_cil_gen_type_rule_member_extra_neg(CuTest *);
+
+void test_cil_gen_user(CuTest *);
+void test_cil_gen_user_dbnull_neg(CuTest *);
+void test_cil_gen_user_currnull_neg(CuTest *);
+void test_cil_gen_user_astnull_neg(CuTest *);
+void test_cil_gen_user_nouser_neg(CuTest *);
+void test_cil_gen_user_xsinfo_neg(CuTest *);
+
+void test_cil_gen_userlevel(CuTest *);
+void test_cil_gen_userlevel_anon_level(CuTest *);
+void test_cil_gen_userlevel_anon_level_neg(CuTest *);
+void test_cil_gen_userlevel_usernull_neg(CuTest *);
+void test_cil_gen_userlevel_userrange_neg(CuTest *);
+void test_cil_gen_userlevel_levelnull_neg(CuTest *);
+void test_cil_gen_userlevel_levelrangeempty_neg(CuTest *);
+void test_cil_gen_userlevel_extra_neg(CuTest *);
+void test_cil_gen_userlevel_dbnull_neg(CuTest *);
+void test_cil_gen_userlevel_currnull_neg(CuTest *);
+void test_cil_gen_userlevel_astnull_neg(CuTest *);
+
+void test_cil_gen_userrange_named(CuTest *);
+void test_cil_gen_userrange_anon(CuTest *);
+void test_cil_gen_userrange_usernull_neg(CuTest *);
+void test_cil_gen_userrange_anonuser_neg(CuTest *);
+void test_cil_gen_userrange_rangenamenull_neg(CuTest *);
+void test_cil_gen_userrange_anonrangeinvalid_neg(CuTest *);
+void test_cil_gen_userrange_anonrangeempty_neg(CuTest *);
+void test_cil_gen_userrange_extra_neg(CuTest *);
+void test_cil_gen_userrange_dbnull_neg(CuTest *);
+void test_cil_gen_userrange_currnull_neg(CuTest *);
+void test_cil_gen_userrange_astnull_neg(CuTest *);
+
+void test_cil_gen_sensitivity(CuTest *);
+void test_cil_gen_sensitivity_dbnull_neg(CuTest *);
+void test_cil_gen_sensitivity_currnull_neg(CuTest *);
+void test_cil_gen_sensitivity_astnull_neg(CuTest *);
+void test_cil_gen_sensitivity_sensnull_neg(CuTest *);
+void test_cil_gen_sensitivity_senslist_neg(CuTest *);
+void test_cil_gen_sensitivity_extra_neg(CuTest *);
+
+void test_cil_gen_sensalias(CuTest *);
+void test_cil_gen_sensalias_dbnull_neg(CuTest *);
+void test_cil_gen_sensalias_currnull_neg(CuTest *);
+void test_cil_gen_sensalias_astnull_neg(CuTest *);
+void test_cil_gen_sensalias_sensnull_neg(CuTest *);
+void test_cil_gen_sensalias_senslist_neg(CuTest *);
+void test_cil_gen_sensalias_aliasnull_neg(CuTest *);
+void test_cil_gen_sensalias_aliaslist_neg(CuTest *);
+void test_cil_gen_sensalias_extra_neg(CuTest *);
+
+void test_cil_gen_category(CuTest *);
+void test_cil_gen_category_dbnull_neg(CuTest *);
+void test_cil_gen_category_astnull_neg(CuTest *);
+void test_cil_gen_category_currnull_neg(CuTest *);
+void test_cil_gen_category_catnull_neg(CuTest *);
+void test_cil_gen_category_catlist_neg(CuTest *);
+void test_cil_gen_category_extra_neg(CuTest *);
+
+void test_cil_gen_catset(CuTest *);
+void test_cil_gen_catset_dbnull_neg(CuTest *);
+void test_cil_gen_catset_currnull_neg(CuTest *);
+void test_cil_gen_catset_astnull_neg(CuTest *);
+void test_cil_gen_catset_namenull_neg(CuTest *);
+void test_cil_gen_catset_setnull_neg(CuTest *);
+void test_cil_gen_catset_namelist_neg(CuTest *);
+void test_cil_gen_catset_extra_neg(CuTest *);
+void test_cil_gen_catset_nodefail_neg(CuTest *);
+void test_cil_gen_catset_notset_neg(CuTest *);
+void test_cil_gen_catset_settolistfail_neg(CuTest *);
+
+void test_cil_gen_catalias(CuTest *);
+void test_cil_gen_catalias_dbnull_neg(CuTest *);
+void test_cil_gen_catalias_currnull_neg(CuTest *);
+void test_cil_gen_catalias_astnull_neg(CuTest *);
+void test_cil_gen_catalias_catnull_neg(CuTest *);
+void test_cil_gen_catalias_aliasnull_neg(CuTest *);
+void test_cil_gen_catalias_extra_neg(CuTest *);
+
+void test_cil_gen_catrange(CuTest *);
+void test_cil_gen_catrange_noname_neg(CuTest *);
+void test_cil_gen_catrange_norange_neg(CuTest *);
+void test_cil_gen_catrange_emptyrange_neg(CuTest *);
+void test_cil_gen_catrange_extrarange_neg(CuTest *);
+void test_cil_gen_catrange_dbnull_neg(CuTest *);
+void test_cil_gen_catrange_currnull_neg(CuTest *);
+void test_cil_gen_catrange_astnull_neg(CuTest *);
+void test_cil_gen_catrange_extra_neg(CuTest *);
+
+void test_cil_gen_roletype(CuTest *tc);
+void test_cil_gen_roletype_currnull_neg(CuTest *tc);
+void test_cil_gen_roletype_dbnull_neg(CuTest *tc);
+void test_cil_gen_roletype_astnull_neg(CuTest *tc);
+void test_cil_gen_roletype_empty_neg(CuTest *tc);
+void test_cil_gen_roletype_rolelist_neg(CuTest *tc);
+void test_cil_gen_roletype_roletype_sublist_neg(CuTest *tc);
+void test_cil_gen_roletype_typelist_neg(CuTest *tc);
+
+void test_cil_gen_userrole(CuTest *tc);
+void test_cil_gen_userrole_currnull_neg(CuTest *tc);
+void test_cil_gen_userrole_dbnull_neg(CuTest *tc);
+void test_cil_gen_userrole_astnull_neg(CuTest *tc);
+void test_cil_gen_userrole_empty_neg(CuTest *tc);
+void test_cil_gen_userrole_userlist_neg(CuTest *tc);
+void test_cil_gen_userrole_userrole_sublist_neg(CuTest *tc);
+void test_cil_gen_userrole_rolelist_neg(CuTest *tc);
+
+void test_cil_gen_classcommon(CuTest *tc);
+void test_cil_gen_classcommon_dbnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_currnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_astnull_neg(CuTest *tc);
+void test_cil_gen_classcommon_missingclassname_neg(CuTest *tc);
+void test_cil_gen_classcommon_noperms_neg(CuTest *tc);
+void test_cil_gen_classcommon_extraperms_neg(CuTest *tc);
+
+void test_cil_gen_catorder(CuTest *tc);
+void test_cil_gen_catorder_dbnull_neg(CuTest *tc);
+void test_cil_gen_catorder_currnull_neg(CuTest *tc);
+void test_cil_gen_catorder_astnull_neg(CuTest *tc);
+void test_cil_gen_catorder_missingcats_neg(CuTest *tc);
+void test_cil_gen_catorder_nosublist_neg(CuTest *tc);
+void test_cil_gen_catorder_nestedcat_neg(CuTest *tc);
+
+void test_cil_gen_dominance(CuTest *tc);
+void test_cil_gen_dominance_dbnull_neg(CuTest *tc);
+void test_cil_gen_dominance_currnull_neg(CuTest *tc);
+void test_cil_gen_dominance_astnull_neg(CuTest *tc);
+void test_cil_gen_dominance_nosensitivities_neg(CuTest *tc);
+void test_cil_gen_dominance_nosublist_neg(CuTest *tc);
+
+void test_cil_gen_senscat(CuTest *tc);
+void test_cil_gen_senscat_nosublist(CuTest *);
+void test_cil_gen_senscat_dbnull_neg(CuTest *tc);
+void test_cil_gen_senscat_currnull_neg(CuTest *tc);
+void test_cil_gen_senscat_astnull_neg(CuTest *tc);
+void test_cil_gen_senscat_nosensitivities_neg(CuTest *tc);
+void test_cil_gen_senscat_sublist_neg(CuTest *);
+void test_cil_gen_senscat_nocat_neg(CuTest *);
+
+void test_cil_fill_level(CuTest *tc);
+void test_cil_fill_level_sensnull_neg(CuTest *tc);
+void test_cil_fill_level_levelnull_neg(CuTest *tc);
+void test_cil_fill_level_nocat(CuTest *tc);
+void test_cil_fill_level_emptycat_neg(CuTest *tc);
+
+void test_cil_gen_level(CuTest *tc);
+void test_cil_gen_level_nameinparens_neg(CuTest *tc);
+void test_cil_gen_level_emptysensparens_neg(CuTest *tc);
+void test_cil_gen_level_extra_neg(CuTest *tc);
+void test_cil_gen_level_emptycat_neg(CuTest *tc);
+void test_cil_gen_level_noname_neg(CuTest *tc);
+void test_cil_gen_level_nosens_neg(CuTest *tc);
+void test_cil_gen_level_dbnull_neg(CuTest *tc);
+void test_cil_gen_level_currnull_neg(CuTest *tc);
+void test_cil_gen_level_astnull_neg(CuTest *tc);
+
+void test_cil_gen_levelrange(CuTest *tc);
+void test_cil_gen_levelrange_rangeinvalid_neg(CuTest *tc);
+void test_cil_gen_levelrange_namenull_neg(CuTest *tc);
+void test_cil_gen_levelrange_rangenull_neg(CuTest *tc);
+void test_cil_gen_levelrange_rangeempty_neg(CuTest *tc);
+void test_cil_gen_levelrange_extra_neg(CuTest *tc);
+void test_cil_gen_levelrange_dbnull_neg(CuTest *tc);
+void test_cil_gen_levelrange_currnull_neg(CuTest *tc);
+void test_cil_gen_levelrange_astnull_neg(CuTest *tc);
+
+void test_cil_gen_constrain(CuTest *tc);
+void test_cil_gen_constrain_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_noclass_neg(CuTest *tc);
+void test_cil_gen_constrain_classset_noperm_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_noclass_neg(CuTest *tc);
+void test_cil_gen_constrain_permset_noperm_neg(CuTest *tc);
+void test_cil_gen_constrain_expression_neg(CuTest *tc);
+void test_cil_gen_constrain_dbnull_neg(CuTest *tc);
+void test_cil_gen_constrain_currnull_neg(CuTest *tc);
+void test_cil_gen_constrain_astnull_neg(CuTest *tc);
+
+void test_cil_fill_context(CuTest *tc);
+void test_cil_fill_context_unnamedlvl(CuTest *tc);
+void test_cil_fill_context_nocontext_neg(CuTest *tc);
+void test_cil_fill_context_nouser_neg(CuTest *tc);
+void test_cil_fill_context_norole_neg(CuTest *tc);
+void test_cil_fill_context_notype_neg(CuTest *tc);
+void test_cil_fill_context_nolowlvl_neg(CuTest *tc);
+void test_cil_fill_context_nohighlvl_neg(CuTest *tc);
+void test_cil_fill_context_unnamedlvl_nocontextlow_neg(CuTest *tc);
+void test_cil_fill_context_unnamedlvl_nocontexthigh_neg(CuTest *tc);
+
+void test_cil_gen_context(CuTest *tc);
+void test_cil_gen_context_notinparens_neg(CuTest *tc);
+void test_cil_gen_context_extralevel_neg(CuTest *tc);
+void test_cil_gen_context_emptycontext_neg(CuTest *tc);
+void test_cil_gen_context_extra_neg(CuTest *tc);
+void test_cil_gen_context_doubleparen_neg(CuTest *tc);
+void test_cil_gen_context_norole_neg(CuTest *tc);
+void test_cil_gen_context_roleinparens_neg(CuTest *tc);
+void test_cil_gen_context_notype_neg(CuTest *tc);
+void test_cil_gen_context_typeinparens_neg(CuTest *tc);
+void test_cil_gen_context_nolevels_neg(CuTest *tc);
+void test_cil_gen_context_nosecondlevel_neg(CuTest *tc);
+void test_cil_gen_context_noname_neg(CuTest *tc);
+void test_cil_gen_context_nouser_neg(CuTest *tc);
+void test_cil_gen_context_dbnull_neg(CuTest *tc);
+void test_cil_gen_context_currnull_neg(CuTest *tc);
+void test_cil_gen_context_astnull_neg(CuTest *tc);
+
+void test_cil_gen_filecon_file(CuTest *tc);
+void test_cil_gen_filecon_dir(CuTest *tc);
+void test_cil_gen_filecon_char(CuTest *tc);
+void test_cil_gen_filecon_block(CuTest *tc);
+void test_cil_gen_filecon_socket(CuTest *tc);
+void test_cil_gen_filecon_pipe(CuTest *tc);
+void test_cil_gen_filecon_symlink(CuTest *tc);
+void test_cil_gen_filecon_any(CuTest *tc);
+void test_cil_gen_filecon_neg(CuTest *tc);
+void test_cil_gen_filecon_anon_context(CuTest *tc);
+void test_cil_gen_filecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_filecon_currnull_neg(CuTest *tc);
+void test_cil_gen_filecon_astnull_neg(CuTest *tc);
+void test_cil_gen_filecon_str1null_neg(CuTest *tc);
+void test_cil_gen_filecon_str1_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_str2null_neg(CuTest *tc);
+void test_cil_gen_filecon_str2_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_classnull_neg(CuTest *tc);
+void test_cil_gen_filecon_class_inparens_neg(CuTest *tc);
+void test_cil_gen_filecon_contextnull_neg(CuTest *tc);
+void test_cil_gen_filecon_context_neg(CuTest *tc);
+void test_cil_gen_filecon_extra_neg(CuTest *tc);
+
+void test_cil_gen_portcon_udp(CuTest *tc);
+void test_cil_gen_portcon_tcp(CuTest *tc);
+void test_cil_gen_portcon_unknownprotocol_neg(CuTest *tc);
+void test_cil_gen_portcon_anon_context(CuTest *tc);
+void test_cil_gen_portcon_portrange(CuTest *tc);
+void test_cil_gen_portcon_portrange_one_neg(CuTest *tc);
+void test_cil_gen_portcon_portrange_morethanone_neg(CuTest *tc);
+void test_cil_gen_portcon_singleport_neg(CuTest *tc);
+void test_cil_gen_portcon_lowport_neg(CuTest *tc);
+void test_cil_gen_portcon_highport_neg(CuTest *tc);
+void test_cil_gen_portcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_portcon_currnull_neg(CuTest *tc);
+void test_cil_gen_portcon_astnull_neg(CuTest *tc);
+void test_cil_gen_portcon_str1null_neg(CuTest *tc);
+void test_cil_gen_portcon_str1parens_neg(CuTest *tc);
+void test_cil_gen_portcon_portnull_neg(CuTest *tc);
+void test_cil_gen_portcon_contextnull_neg(CuTest *tc);
+void test_cil_gen_portcon_context_neg(CuTest *tc);
+void test_cil_gen_portcon_extra_neg(CuTest *tc);
+
+void test_cil_fill_ipaddr(CuTest *tc);
+void test_cil_fill_ipaddr_addrnodenull_neg(CuTest *tc);
+void test_cil_fill_ipaddr_addrnull_neg(CuTest *tc);
+void test_cil_fill_ipaddr_addrinparens_neg(CuTest *tc);
+void test_cil_fill_ipaddr_extra_neg(CuTest *tc);
+
+void test_cil_gen_nodecon(CuTest *tc);
+void test_cil_gen_nodecon_anon_context(CuTest *tc);
+void test_cil_gen_nodecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_currnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_astnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_ipnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_ipanon(CuTest *tc);
+void test_cil_gen_nodecon_ipanon_neg(CuTest *tc);
+void test_cil_gen_nodecon_netmasknull_neg(CuTest *tc);
+void test_cil_gen_nodecon_netmaskanon(CuTest *tc);
+void test_cil_gen_nodecon_netmaskanon_neg(CuTest *tc);
+void test_cil_gen_nodecon_contextnull_neg(CuTest *tc);
+void test_cil_gen_nodecon_context_neg(CuTest *tc);
+void test_cil_gen_nodecon_extra_neg(CuTest *tc);
+
+void test_cil_gen_genfscon(CuTest *tc);
+void test_cil_gen_genfscon_anon_context(CuTest *tc);
+void test_cil_gen_genfscon_dbnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_currnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_astnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_typenull_neg(CuTest *tc);
+void test_cil_gen_genfscon_typeparens_neg(CuTest *tc);
+void test_cil_gen_genfscon_pathnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_pathparens_neg(CuTest *tc);
+void test_cil_gen_genfscon_contextnull_neg(CuTest *tc);
+void test_cil_gen_genfscon_context_neg(CuTest *tc);
+void test_cil_gen_genfscon_extra_neg(CuTest *tc);
+
+void test_cil_gen_netifcon(CuTest *tc);
+void test_cil_gen_netifcon_nested(CuTest *tc);
+void test_cil_gen_netifcon_nested_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_emptysecondlist_neg(CuTest *tc);
+void test_cil_gen_netifcon_extra_nested_secondlist_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_missingobjects_neg(CuTest *tc);
+void test_cil_gen_netifcon_nested_secondnested_missingobjects_neg(CuTest *tc);
+void test_cil_gen_netifcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_currnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_astnull_neg(CuTest *tc);
+void test_cil_gen_netifcon_ethmissing_neg(CuTest *tc);
+void test_cil_gen_netifcon_interfacemissing_neg(CuTest *tc);
+void test_cil_gen_netifcon_packetmissing_neg(CuTest *tc);
+
+void test_cil_gen_pirqcon(CuTest *tc);
+void test_cil_gen_pirqcon_pirqnotint_neg(CuTest *tc);
+void test_cil_gen_pirqcon_nopirq_neg(CuTest *tc);
+void test_cil_gen_pirqcon_pirqrange_neg(CuTest *tc);
+void test_cil_gen_pirqcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_pirqcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_pirqcon_extra_neg(CuTest *tc);
+void test_cil_gen_pirqcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_pirqcon_currnull_neg(CuTest *tc);
+void test_cil_gen_pirqcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_iomemcon(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_firstnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_secondnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_empty_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_singleiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemrange_morethantwoiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_iomemnotint_neg(CuTest *tc);
+void test_cil_gen_iomemcon_noiomem_neg(CuTest *tc);
+void test_cil_gen_iomemcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_iomemcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_iomemcon_extra_neg(CuTest *tc);
+void test_cil_gen_iomemcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_iomemcon_currnull_neg(CuTest *tc);
+void test_cil_gen_iomemcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_ioportcon(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_firstnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_secondnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_empty_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_singleioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportrange_morethantwoioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_ioportnotint_neg(CuTest *tc);
+void test_cil_gen_ioportcon_noioport_neg(CuTest *tc);
+void test_cil_gen_ioportcon_nocontext_neg(CuTest *tc);
+void test_cil_gen_ioportcon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_ioportcon_extra_neg(CuTest *tc);
+void test_cil_gen_ioportcon_dbnull_neg(CuTest *tc);
+void test_cil_gen_ioportcon_currnull_neg(CuTest *tc);
+void test_cil_gen_ioportcon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_pcidevicecon(CuTest *tc);
+void test_cil_gen_pcidevicecon_pcidevicenotint_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_nopcidevice_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_pcidevicerange_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_nocontext_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_anoncontext_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_extra_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_dbnull_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_currnull_neg(CuTest *tc);
+void test_cil_gen_pcidevicecon_astnull_neg(CuTest *tc);
+
+void test_cil_gen_fsuse_anoncontext(CuTest *tc);
+void test_cil_gen_fsuse_anoncontext_neg(CuTest *tc);
+void test_cil_gen_fsuse_xattr(CuTest *tc);
+void test_cil_gen_fsuse_task(CuTest *tc);
+void test_cil_gen_fsuse_transition(CuTest *tc);
+void test_cil_gen_fsuse_invalidtype_neg(CuTest *tc);
+void test_cil_gen_fsuse_notype_neg(CuTest *tc);
+void test_cil_gen_fsuse_typeinparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_nofilesystem_neg(CuTest *tc);
+void test_cil_gen_fsuse_filesysteminparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_nocontext_neg(CuTest *tc);
+void test_cil_gen_fsuse_emptyconparens_neg(CuTest *tc);
+void test_cil_gen_fsuse_extra_neg(CuTest *tc);
+void test_cil_gen_fsuse_dbnull_neg(CuTest *tc);
+void test_cil_gen_fsuse_currnull_neg(CuTest *tc);
+void test_cil_gen_fsuse_astnull_neg(CuTest *tc);
+
+void test_cil_gen_macro_noparams(CuTest *tc);
+void test_cil_gen_macro_type(CuTest *tc);
+void test_cil_gen_macro_role(CuTest *tc);
+void test_cil_gen_macro_user(CuTest *tc);
+void test_cil_gen_macro_sensitivity(CuTest *tc);
+void test_cil_gen_macro_category(CuTest *tc);
+void test_cil_gen_macro_catset(CuTest *tc);
+void test_cil_gen_macro_level(CuTest *tc);
+void test_cil_gen_macro_class(CuTest *tc);
+void test_cil_gen_macro_classmap(CuTest *tc);
+void test_cil_gen_macro_permset(CuTest *tc);
+void test_cil_gen_macro_duplicate(CuTest *tc);
+void test_cil_gen_macro_duplicate_neg(CuTest *tc);
+void test_cil_gen_macro_unknown_neg(CuTest *tc);
+void test_cil_gen_macro_dbnull_neg(CuTest *tc);
+void test_cil_gen_macro_currnull_neg(CuTest *tc);
+void test_cil_gen_macro_astnull_neg(CuTest *tc);
+void test_cil_gen_macro_unnamed_neg(CuTest *tc);
+void test_cil_gen_macro_noparam_name_neg(CuTest *tc);
+void test_cil_gen_macro_noparam_neg(CuTest *tc);
+void test_cil_gen_macro_nosecondparam_neg(CuTest *tc);
+void test_cil_gen_macro_emptyparam_neg(CuTest *tc);
+void test_cil_gen_macro_paramcontainsperiod_neg(CuTest *tc);
+
+void test_cil_gen_call(CuTest *tc);
+void test_cil_gen_call_noargs(CuTest *tc);
+void test_cil_gen_call_anon(CuTest *tc);
+void test_cil_gen_call_empty_call_neg(CuTest *tc);
+void test_cil_gen_call_dbnull_neg(CuTest *tc);
+void test_cil_gen_call_currnull_neg(CuTest *tc);
+void test_cil_gen_call_astnull_neg(CuTest *tc);
+void test_cil_gen_call_name_inparens_neg(CuTest *tc);
+void test_cil_gen_call_noname_neg(CuTest *tc);
+
+void test_cil_gen_optional(CuTest *tc);
+void test_cil_gen_optional_emptyoptional(CuTest *tc);
+void test_cil_gen_optional_dbnull_neg(CuTest *tc);
+void test_cil_gen_optional_currnull_neg(CuTest *tc);
+void test_cil_gen_optional_astnull_neg(CuTest *tc);
+void test_cil_gen_optional_unnamed_neg(CuTest *tc);
+void test_cil_gen_optional_extra_neg(CuTest *tc);
+void test_cil_gen_optional_nameinparens_neg(CuTest *tc);
+void test_cil_gen_optional_norule_neg(CuTest *tc);
+
+void test_cil_gen_policycap(CuTest *tc);
+void test_cil_gen_policycap_noname_neg(CuTest *tc);
+void test_cil_gen_policycap_nameinparens_neg(CuTest *tc);
+void test_cil_gen_policycap_extra_neg(CuTest *tc);
+void test_cil_gen_policycap_dbnull_neg(CuTest *tc);
+void test_cil_gen_policycap_currnull_neg(CuTest *tc);
+void test_cil_gen_policycap_astnull_neg(CuTest *tc);
+
+void test_cil_gen_ipaddr_ipv4(CuTest *tc);
+void test_cil_gen_ipaddr_ipv4_neg(CuTest *tc);
+void test_cil_gen_ipaddr_ipv6(CuTest *tc);
+void test_cil_gen_ipaddr_ipv6_neg(CuTest *tc);
+void test_cil_gen_ipaddr_noname_neg(CuTest *tc);
+void test_cil_gen_ipaddr_nameinparens_neg(CuTest *tc);
+void test_cil_gen_ipaddr_noip_neg(CuTest *tc);
+void test_cil_gen_ipaddr_ipinparens_neg(CuTest *tc);
+void test_cil_gen_ipaddr_extra_neg(CuTest *tc);
+void test_cil_gen_ipaddr_dbnull_neg(CuTest *tc);
+void test_cil_gen_ipaddr_currnull_neg(CuTest *tc);
+void test_cil_gen_ipaddr_astnull_neg(CuTest *tc);
+/*
+cil_build_ast test cases
+*/
+void test_cil_build_ast(CuTest *);
+void test_cil_build_ast_dbnull_neg(CuTest *);
+void test_cil_build_ast_astnull_neg(CuTest *);
+void test_cil_build_ast_suberr_neg(CuTest *);
+void test_cil_build_ast_treenull_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_block(CuTest *);
+void test_cil_build_ast_node_helper_block_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_blockinherit(CuTest *);
+void test_cil_build_ast_node_helper_blockinherit_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_permset(CuTest *);
+void test_cil_build_ast_node_helper_permset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_in(CuTest *);
+void test_cil_build_ast_node_helper_in_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_class(CuTest *);
+void test_cil_build_ast_node_helper_class_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classpermset(CuTest *);
+void test_cil_build_ast_node_helper_classpermset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classmap(CuTest *);
+void test_cil_build_ast_node_helper_classmap_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_classmapping(CuTest *);
+void test_cil_build_ast_node_helper_classmapping_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_common(CuTest *);
+void test_cil_build_ast_node_helper_common_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sid(CuTest *);
+void test_cil_build_ast_node_helper_sid_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sidcontext(CuTest *);
+void test_cil_build_ast_node_helper_sidcontext_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_user(CuTest *);
+void test_cil_build_ast_node_helper_user_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userlevel(CuTest *);
+void test_cil_build_ast_node_helper_userlevel_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userrange(CuTest *);
+void test_cil_build_ast_node_helper_userrange_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type(CuTest *);
+void test_cil_build_ast_node_helper_type_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typeattribute(CuTest *);
+void test_cil_build_ast_node_helper_typeattribute_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_boolif(CuTest *);
+void test_cil_build_ast_node_helper_boolif_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_tunif(CuTest *);
+void test_cil_build_ast_node_helper_tunif_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_condblock_true(CuTest *);
+void test_cil_build_ast_node_helper_condblock_true_neg(CuTest *);
+void test_cil_build_ast_node_helper_condblock_false(CuTest *);
+void test_cil_build_ast_node_helper_condblock_false_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typealias(CuTest *);
+void test_cil_build_ast_node_helper_typealias_notype_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typebounds(CuTest *);
+void test_cil_build_ast_node_helper_typebounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typepermissive(CuTest *);
+void test_cil_build_ast_node_helper_typepermissive_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_nametypetransition(CuTest *);
+void test_cil_build_ast_node_helper_nametypetransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_rangetransition(CuTest *);
+void test_cil_build_ast_node_helper_rangetransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_typeattributeset(CuTest *);
+void test_cil_build_ast_node_helper_typeattributeset_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_userbounds(CuTest *);
+void test_cil_build_ast_node_helper_userbounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_role(CuTest *);
+void test_cil_build_ast_node_helper_role_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_roletransition(CuTest *);
+void test_cil_build_ast_node_helper_roletransition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_roleallow(CuTest *);
+void test_cil_build_ast_node_helper_roleallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_rolebounds(CuTest *);
+void test_cil_build_ast_node_helper_rolebounds_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_allow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_allow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_auditallow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_auditallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_dontaudit(CuTest *);
+void test_cil_build_ast_node_helper_avrule_dontaudit_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_avrule_neverallow(CuTest *);
+void test_cil_build_ast_node_helper_avrule_neverallow_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_transition(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_transition_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_change(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_change_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_type_rule_member(CuTest *);
+void test_cil_build_ast_node_helper_type_rule_member_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_bool(CuTest *);
+void test_cil_build_ast_node_helper_bool_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_bool_tunable(CuTest *);
+void test_cil_build_ast_node_helper_bool_tunable_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_else(CuTest *);
+void test_cil_build_ast_node_helper_else_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sensitivity(CuTest *);
+void test_cil_build_ast_node_helper_sensitivity_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_sensalias(CuTest *);
+void test_cil_build_ast_node_helper_sensalias_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_category(CuTest *);
+void test_cil_build_ast_node_helper_category_neg(CuTest *);
+
+void test_cil_build_ast_node_helper_catset(CuTest *tc);
+void test_cil_build_ast_node_helper_catset_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catorder(CuTest *tc);
+void test_cil_build_ast_node_helper_catorder_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catalias(CuTest *tc);
+void test_cil_build_ast_node_helper_catalias_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_catrange(CuTest *tc);
+void test_cil_build_ast_node_helper_catrange_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_roletype(CuTest *tc);
+void test_cil_build_ast_node_helper_roletype_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_userrole(CuTest *tc);
+void test_cil_build_ast_node_helper_userrole_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_classcommon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_classcommon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_dominance(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_dominance_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_senscat(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_senscat_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_level(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_level_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_levelrange(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_levelrange_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_constrain(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_constrain_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_mlsconstrain(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_mlsconstrain_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_context(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_context_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_filecon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_filecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_portcon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_portcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_nodecon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_nodecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_genfscon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_genfscon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_netifcon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_netifcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_pirqcon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_pirqcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_iomemcon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_iomemcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_ioportcon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_ioportcon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_pcidevicecon(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_pcidevicecon_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_fsuse(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_fsuse_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_macro(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_macro_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_macro_nested_macro_neg(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_macro_nested_tunif_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_call(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_call_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_optional(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_optional_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_policycap(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_policycap_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_gen_ipaddr(CuTest *tc);
+void test_cil_build_ast_node_helper_gen_ipaddr_neg(CuTest *tc);
+
+void test_cil_build_ast_node_helper_extraargsnull_neg(CuTest *);
+
+void test_cil_build_ast_last_child_helper(CuTest *);
+void test_cil_build_ast_last_child_helper_extraargsnull_neg(CuTest *);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_copy_ast.c b/libsepol/cil/test/unit/test_cil_copy_ast.c
new file mode 100644
index 0000000..0053e85
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_copy_ast.c
@@ -0,0 +1,2571 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_copy_ast.h"
+#include "../../src/cil_build_ast.h"
+#include "../../src/cil_resolve_ast.h"
+
+#define CIL_TEST_SYM_SIZE 1
+
+int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args);
+
+struct cil_args_copy {
+ struct cil_tree_node *dest;
+ struct cil_db *db;
+};
+
+struct cil_args_copy *gen_copy_args(struct cil_tree_node *node, struct cil_db *db)
+{
+ struct cil_args_copy *args = cil_malloc(sizeof(*args));
+ args->dest = node;
+ args->db = db;
+
+ return args;
+}
+
+void test_cil_copy_list(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ struct cil_list *cil_l;
+
+ gen_test_tree(&test_tree, line);
+ cil_list_init(&cil_l);
+
+ cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+ struct cil_list *copy_list;
+ cil_list_init(©_list);
+
+ int rc =cil_copy_list(cil_l, ©_list);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+ CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+ CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+ CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+}
+
+void test_cil_copy_list_sublist(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ struct cil_list *cil_l;
+
+ gen_test_tree(&test_tree, line);
+ cil_list_init(&cil_l);
+
+ cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+ struct cil_list *copy_list;
+ cil_list_init(©_list);
+
+ int rc = cil_copy_list(cil_l, ©_list);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+ CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+ CuAssertStrEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->data, ((struct cil_list *)cil_l->head->next->next->data)->head->data);
+ CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+ CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+ CuAssertIntEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->flavor, ((struct cil_list *)cil_l->head->next->next->data)->head->flavor);
+}
+
+void test_cil_copy_list_sublist_extra(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", "(", "foo3", ")", "foo4", ")", NULL};
+
+ struct cil_tree *test_tree;
+ struct cil_list *cil_l;
+
+ gen_test_tree(&test_tree, line);
+ cil_list_init(&cil_l);
+
+ cil_set_to_list(test_tree->root->cl_head, cil_l, 1);
+
+ struct cil_list *copy_list;
+ cil_list_init(©_list);
+
+ int rc = cil_copy_list(cil_l, ©_list);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, copy_list->head->data, cil_l->head->data);
+ CuAssertStrEquals(tc, copy_list->head->next->data, cil_l->head->next->data);
+ CuAssertStrEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->data, ((struct cil_list *)cil_l->head->next->next->data)->head->data);
+ CuAssertStrEquals(tc, copy_list->head->next->next->next->data, cil_l->head->next->next->next->data);
+ CuAssertIntEquals(tc, copy_list->head->flavor, cil_l->head->flavor);
+ CuAssertIntEquals(tc, copy_list->head->next->flavor, cil_l->head->next->flavor);
+ CuAssertIntEquals(tc, ((struct cil_list *)copy_list->head->next->next->data)->head->flavor, ((struct cil_list *)cil_l->head->next->next->data)->head->flavor);
+ CuAssertIntEquals(tc, copy_list->head->next->next->next->flavor, cil_l->head->next->next->next->flavor);
+}
+
+void test_cil_copy_list_orignull_neg(CuTest *tc) {
+ char *line[] = {"(", "foo1", "foo2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ struct cil_list *cil_l = NULL;
+
+ gen_test_tree(&test_tree, line);
+
+ struct cil_list *copy_list;
+ cil_list_init(©_list);
+
+ int rc = cil_copy_list(cil_l, ©_list);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+ CuAssertPtrEquals(tc, copy_list->head, NULL);
+}
+
+void test_cil_copy_block(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_block(test_db, test_tree->root->cl_head->cl_head, test_ast_node, 0);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK][CIL_SYM_BLOCKS]);
+
+ int rc = cil_copy_block(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_perm(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_class *new_node;
+ cil_class_init(&new_node);
+
+ struct cil_tree_node *new_tree_node;
+ cil_tree_node_init(&new_tree_node);
+ new_tree_node->data = new_node;
+ new_tree_node->flavor = CIL_CLASS;
+
+ test_ast_node->parent = new_tree_node;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+ cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head, test_ast_node);
+ int rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next, test_ast_node);
+ rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ cil_gen_perm(test_db, test_tree->root->cl_head->cl_head->next->next->cl_head->next->next, test_ast_node);
+ rc = cil_copy_perm(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+
+}
+
+void test_cil_copy_class(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_class(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+ int rc = cil_copy_class(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_common(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_common(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+ int rc = cil_copy_common(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_classcommon(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ char *test_key = test_tree->root->cl_head->cl_head->next->data;
+ struct cil_class *test_cls;
+ cil_class_init(&test_cls);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_insert(&test_db->symtab[CIL_SYM_CLASSES], (hashtab_key_t)test_key, (struct cil_symtab_datum*)test_cls, test_ast_node);
+
+ test_ast_node->data = test_cls;
+ test_ast_node->flavor = CIL_CLASS;
+
+ cil_gen_classcommon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_classcommon *test_copy;
+ cil_classcommon_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_CLASS_SYM_SIZE);
+
+ int rc = cil_copy_classcommon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_classcommon *)test_ast_node->data)->class_str, test_copy->class_str);
+ CuAssertStrEquals(tc, ((struct cil_classcommon *)test_ast_node->data)->common_str, test_copy->common_str);
+}
+
+void test_cil_copy_sid(CuTest *tc) {
+ char *line[] = {"(", "sid", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_sid(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_sid(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_sidcontext(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_sidcontext(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_user *)test_copy->data)->datum.name,
+ ((struct cil_user *)test_ast_node->data)->datum.name);
+}
+
+void test_cil_copy_user(CuTest *tc) {
+ char *line[] = {"(", "user", "sysadm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_user(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_user(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_role(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_role(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_role(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_userrole(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_userrole(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_userrole *test_copy;
+ cil_userrole_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_userrole(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_userrole *)test_ast_node->data)->user_str, test_copy->user_str);
+ CuAssertStrEquals(tc, ((struct cil_userrole *)test_ast_node->data)->role_str, test_copy->role_str);
+}
+
+void test_cil_copy_type(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_type(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_type(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_typealias(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_typealias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_typealias(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_typeattribute(CuTest *tc) {
+ char *line[] = {"(", "typettribute", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_typeattribute(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_typeattribute(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_bool(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_bool(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_BOOL);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_bool(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertIntEquals(tc, ((struct cil_bool *)test_copy->data)->value,
+ ((struct cil_bool *)test_ast_node->data)->value);
+}
+
+void test_cil_copy_type_rule(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_type_rule(test_tree->root->cl_head->cl_head, test_ast_node, CIL_TYPE_TRANSITION);
+
+ struct cil_type_rule *test_copy;
+ cil_type_rule_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_type_rule(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertIntEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->rule_kind, test_copy->rule_kind);
+ CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->src_str, test_copy->src_str);
+ CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->tgt_str, test_copy->tgt_str);
+ CuAssertStrEquals(tc, ((struct cil_type_rule *)test_ast_node->data)->obj_str, test_copy->obj_str);
+}
+
+void test_cil_copy_avrule(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ cil_gen_avrule(test_current, test_ast_node, CIL_AVRULE_ALLOWED);
+
+ struct cil_avrule *test_copy;
+ cil_avrule_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_avrule(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->rule_kind, test_copy->rule_kind);
+ CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->src_str, test_copy->src_str);
+ CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->tgt_str, test_copy->tgt_str);
+ CuAssertStrEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->class_str, test_copy->classpermset->class_str);
+ CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->flavor, test_copy->classpermset->permset->perms_list_str->head->flavor);
+ CuAssertStrEquals(tc, (char*)((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->data, (char*)test_copy->classpermset->permset->perms_list_str->head->data);
+ CuAssertIntEquals(tc, ((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->next->flavor, test_copy->classpermset->permset->perms_list_str->head->next->flavor);
+ CuAssertStrEquals(tc, (char*)((struct cil_avrule *)test_ast_node->data)->classpermset->permset->perms_list_str->head->next->data, (char*)test_copy->classpermset->permset->perms_list_str->head->next->data);
+}
+
+void test_cil_copy_sens(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_sensitivity(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_sens(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_sensalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_sensalias(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_sensalias *)test_copy->data)->sens_str,
+ ((struct cil_sensalias *)test_ast_node->data)->sens_str);
+}
+
+void test_cil_copy_cat(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_category(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_cat(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_catalias(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_catalias(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_catalias(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_catalias *)test_copy->data)->cat_str,
+ ((struct cil_catalias *)test_ast_node->data)->cat_str);
+}
+
+void test_cil_copy_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_senscat(test_db, test_tree->root->cl_head->next->next->next->next->next->next->cl_head, test_ast_node);
+
+ struct cil_senscat *test_copy;
+ cil_senscat_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_senscat(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_senscat *)test_ast_node->data)->sens_str, test_copy->sens_str);
+ CuAssertStrEquals(tc, (char*)((struct cil_senscat *)test_ast_node->data)->catset->cat_list_str->head->data,
+ (char*)test_copy->catset->cat_list_str->head->data);
+ CuAssertStrEquals(tc, (char*)((struct cil_senscat *)test_ast_node->data)->catset->cat_list_str->head->next->data,
+ (char*)test_copy->catset->cat_list_str->head->next->data);
+}
+
+void test_cil_copy_catorder(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_catorder(test_db, test_tree->root->cl_head->next->next->cl_head, test_ast_node);
+
+ struct cil_catorder *test_copy;
+ cil_catorder_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_catorder(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, (char*)((struct cil_catorder *)test_ast_node->data)->cat_list_str->head->data, (char*)test_copy->cat_list_str->head->data);
+ CuAssertStrEquals(tc, (char*)((struct cil_catorder *)test_ast_node->data)->cat_list_str->head->next->data, (char*)test_copy->cat_list_str->head->next->data);
+}
+
+void test_cil_copy_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_dominance(test_db, test_tree->root->cl_head->next->next->next->cl_head, test_ast_node);
+
+ struct cil_sens_dominates *test_copy;
+ cil_sens_dominates_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_dominance(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, (char*)((struct cil_sens_dominates *)test_ast_node->data)->sens_list_str->head->data, (char*)test_copy->sens_list_str->head->data);
+ CuAssertStrEquals(tc, (char*)((struct cil_sens_dominates *)test_ast_node->data)->sens_list_str->head->next->data, (char*)test_copy->sens_list_str->head->next->data);
+}
+
+void test_cil_copy_level(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_level(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_fill_level(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_level(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+ cil_level_init((struct cil_level**)&test_copy->data);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_fill_level((struct cil_level*)test_ast_node->data, (struct cil_level*)test_copy->data);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_level *)test_copy->data)->sens_str,
+ ((struct cil_level *)test_ast_node->data)->sens_str);
+}
+
+void test_cil_copy_context(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_context(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_netifcon(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_netifcon *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_netifcon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, test_copy->interface_str,
+ ((struct cil_netifcon *)test_ast_node->data)->interface_str);
+ CuAssertStrEquals(tc, test_copy->if_context_str,
+ ((struct cil_netifcon *)test_ast_node->data)->if_context_str);
+ CuAssertStrEquals(tc, test_copy->packet_context_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context_str);
+}
+
+void test_cil_copy_netifcon_nested(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_netifcon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_netifcon *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_netifcon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, test_copy->interface_str,
+ ((struct cil_netifcon *)test_ast_node->data)->interface_str);
+ CuAssertStrEquals(tc, test_copy->if_context_str,
+ ((struct cil_netifcon *)test_ast_node->data)->if_context_str);
+ CuAssertStrEquals(tc, test_copy->packet_context_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context_str);
+ CuAssertStrEquals(tc, test_copy->packet_context->user_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context->user_str);
+ CuAssertStrEquals(tc, test_copy->packet_context->role_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context->role_str);
+ CuAssertStrEquals(tc, test_copy->packet_context->type_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context->type_str);
+ CuAssertStrEquals(tc, test_copy->packet_context->range_str,
+ ((struct cil_netifcon *)test_ast_node->data)->packet_context->range_str);
+}
+
+void test_cil_copy_fill_context(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "range", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+ cil_context_init((struct cil_context**)&test_copy->data);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_fill_context((struct cil_context*)test_ast_node->data, (struct cil_context*)test_copy->data);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->user_str,
+ ((struct cil_context *)test_ast_node->data)->user_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->role_str,
+ ((struct cil_context *)test_ast_node->data)->role_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->type_str,
+ ((struct cil_context *)test_ast_node->data)->type_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->range_str,
+ ((struct cil_context *)test_ast_node->data)->range_str);
+}
+
+void test_cil_copy_fill_context_anonrange(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_context(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+ cil_context_init((struct cil_context**)&test_copy->data);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_fill_context((struct cil_context*)test_ast_node->data, (struct cil_context*)test_copy->data);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->user_str,
+ ((struct cil_context *)test_ast_node->data)->user_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->role_str,
+ ((struct cil_context *)test_ast_node->data)->role_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->type_str,
+ ((struct cil_context *)test_ast_node->data)->type_str);
+ CuAssertStrEquals(tc, ((struct cil_context *)test_copy->data)->range_str,
+ ((struct cil_context *)test_ast_node->data)->range_str);
+}
+
+void test_cil_copy_call(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_call(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_call *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_call(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, test_copy->macro_str, ((struct cil_call *)test_ast_node->data)->macro_str);
+}
+
+void test_cil_copy_optional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_optional(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_optional(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_nodecon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "ipaddr", "ipaddr", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_nodecon *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_nodecon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, test_copy->addr_str,
+ ((struct cil_nodecon *)test_ast_node->data)->addr_str);
+ CuAssertStrEquals(tc, test_copy->mask_str,
+ ((struct cil_nodecon *)test_ast_node->data)->mask_str);
+ CuAssertStrEquals(tc, test_copy->context_str,
+ ((struct cil_nodecon *)test_ast_node->data)->context_str);
+}
+
+void test_cil_copy_nodecon_anon(CuTest *tc) {
+ char *line[] = {"(", "nodecon", "(", "192.168.1.1", ")", "(", "192.168.1.1", ")", "(", "user", "role", "type", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_nodecon(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_nodecon *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_nodecon(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, test_copy->addr_str,
+ ((struct cil_nodecon *)test_ast_node->data)->addr_str);
+ CuAssertStrEquals(tc, test_copy->mask_str,
+ ((struct cil_nodecon *)test_ast_node->data)->mask_str);
+ CuAssertStrEquals(tc, test_copy->context_str,
+ ((struct cil_nodecon *)test_ast_node->data)->context_str);
+}
+
+void test_cil_copy_fill_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ struct cil_ipaddr *new;
+ cil_ipaddr_init(&new);
+ struct cil_ipaddr *old;
+ cil_ipaddr_init(&new);
+
+ old = (struct cil_ipaddr*)test_ast_node->data;
+ int rc = cil_copy_fill_ipaddr(old, new);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+
+ CuAssertIntEquals(tc, old->family, new->family);
+}
+
+void test_cil_copy_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_ipaddr(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_tree_node *test_copy;
+ cil_tree_node_init(&test_copy);
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_ipaddr(test_db, test_ast_node->data, &test_copy->data, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_conditional(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_list_item *curr_old;
+ curr_old = ((struct cil_booleanif*)test_ast_node->data)->expr_stack->head;
+
+ struct cil_conditional *cond_new;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_conditional(test_db, curr_old->data, (void**)&cond_new, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+
+ CuAssertStrEquals(tc, ((struct cil_conditional*)curr_old->data)->str, cond_new->str);
+ CuAssertIntEquals(tc, ((struct cil_conditional*)curr_old->data)->flavor, cond_new->flavor);
+}
+
+void test_cil_copy_boolif(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_boolif(test_db, test_tree->root->cl_head->cl_head, test_ast_node);
+
+ struct cil_booleanif *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_boolif(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_constrain(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+ struct cil_constrain *test_copy;
+
+ symtab_t sym;
+ symtab_init(&sym, CIL_TEST_SYM_SIZE);
+
+ int rc = cil_copy_constrain(test_db, test_ast_node->data, (void**)&test_copy, &sym);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+ CuAssertStrEquals(tc, ((struct cil_constrain*)test_copy)->classpermset->class_str, ((struct cil_constrain *)test_ast_node->data)->classpermset->class_str);
+}
+/*
+void test_cil_copy_ast(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *test_copy;
+ cil_constrain_init(&test_copy);
+ cil_list_init(&test_copy->expr);
+
+ int rc = cil_copy_ast(((struct cil_constrain *)test_ast_node->data)->expr, test_copy->expr);
+ CuAssertIntEquals(tc, rc, SEPOL_OK);
+}
+
+void test_cil_copy_ast_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_gen_constrain(test_db, test_tree->root->cl_head->cl_head, test_ast_node, CIL_MLSCONSTRAIN);
+
+ struct cil_tree_node *test_current;
+ test_current = test_tree->root->cl_head->cl_head;
+
+ struct cil_constrain *test_copy;
+ cil_constrain_init(&test_copy);
+ cil_list_init(&test_copy->expr);
+
+ int rc = cil_copy_ast(((struct cil_constrain *)test_ast_node->data)->expr, test_copy->expr);
+ CuAssertIntEquals(tc, rc, SEPOL_ERR);
+}
+*/
+/* node_helper functions */
+
+void test_cil_copy_node_helper_block(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_block_merge(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_perm(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_class *test_class;
+ cil_class_init(&test_class);
+
+ struct cil_tree_node *parent_node;
+ cil_tree_node_init(&parent_node);
+ parent_node->flavor = CIL_CLASS;
+ parent_node->data = test_class;
+ struct cil_tree_node *root;
+ cil_tree_node_init(&root);
+ root->flavor = CIL_ROOT;
+ parent_node->parent = root;
+
+ struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_perm_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_class(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_class_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_common(CuTest *tc) {
+ char *line[] = {"(", "common", "test", "(", "read", "write", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_common_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", "write", "open", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_classcommon(CuTest *tc) {
+ char *line[] = {"(", "classcommon", "file", "file", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sid(CuTest *tc) {
+ char *line[] = {"(", "sid", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sid_merge(CuTest *tc) {
+ char *line[] = {"(", "sid", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_user(CuTest *tc) {
+ char *line[] = {"(", "user", "sysadm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_user_merge(CuTest *tc) {
+ char *line[] = {"(", "user", "sysadm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_role(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_role_merge(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_userrole(CuTest *tc) {
+ char *line[] = {"(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type(CuTest *tc) {
+ char *line[] = {"(", "type", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type_merge(CuTest *tc) {
+ char *line[] = {"(", "type", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typeattribute(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typeattribute_merge(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typealias(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_typealias_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_bool(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_bool_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_avrule(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "file", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_type_rule(CuTest *tc) {
+ char *line[] = {"(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sens(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sens_merge(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_sensalias_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_cat(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_cat_merge(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catalias(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catalias_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_senscat *test_senscat;
+ cil_senscat_init(&test_senscat);
+
+ struct cil_tree_node *parent_node;
+ cil_tree_node_init(&parent_node);
+ parent_node->flavor = CIL_SENSCAT;
+ parent_node->data = test_senscat;
+
+ struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_catorder(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_catorder *test_catorder;
+ cil_catorder_init(&test_catorder);
+
+ struct cil_tree_node *parent_node;
+ cil_tree_node_init(&parent_node);
+ parent_node->flavor = CIL_CATORDER;
+ parent_node->data = test_catorder;
+
+ struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_sens *test_sens;
+ cil_sens_init(&test_sens);
+
+ struct cil_tree_node *parent_node;
+ cil_tree_node_init(&parent_node);
+ parent_node->flavor = CIL_SENS;
+ parent_node->data = test_sens;
+
+ struct cil_args_copy *extra_args = gen_copy_args(parent_node, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_level(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_level_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_context(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_context_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_netifcon(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_call(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_optional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_optional_merge(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_ipaddr_dup_neg(CuTest *tc) {
+ char *line[] = {"(", "ipaddr", "ip", "192.168.1.1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db->ast->root, test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_boolif(CuTest *tc) {
+ char *line[] = {"(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_mlsconstrain(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, finished, 0);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_copy_node_helper_orignull_neg(CuTest *tc) {
+ char *line[] = {"(", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ uint32_t finished = 0;
+
+ struct cil_args_copy *extra_args = gen_copy_args(test_db2->ast->root, test_db2);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_copy_node_helper_extraargsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "l1", "l2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_db *test_db2;
+ cil_db_init(&test_db2);
+
+ struct cil_args_copy *extra_args = NULL;
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_copy_node_helper(test_db->ast->root->cl_head, &finished, extra_args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_copy_ast.h b/libsepol/cil/test/unit/test_cil_copy_ast.h
new file mode 100644
index 0000000..b1aace1
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_copy_ast.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_COPY_AST_H_
+#define TEST_CIL_COPY_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_copy_list(CuTest *);
+void test_cil_copy_list_sublist(CuTest *);
+void test_cil_copy_list_sublist_extra(CuTest *);
+void test_cil_copy_list_orignull_neg(CuTest *);
+
+void test_cil_copy_block(CuTest *);
+void test_cil_copy_node_helper_block(CuTest *tc);
+void test_cil_copy_node_helper_block_merge(CuTest *tc);
+
+void test_cil_copy_perm(CuTest *);
+void test_cil_copy_node_helper_perm(CuTest *tc);
+void test_cil_copy_node_helper_perm_neg(CuTest *tc);
+
+void test_cil_copy_class(CuTest *);
+void test_cil_copy_node_helper_class(CuTest *tc);
+void test_cil_copy_node_helper_class_dup_neg(CuTest *tc);
+
+void test_cil_copy_common(CuTest *);
+void test_cil_copy_node_helper_common(CuTest *tc);
+void test_cil_copy_node_helper_common_dup_neg(CuTest *tc);
+
+void test_cil_copy_classcommon(CuTest *);
+void test_cil_copy_node_helper_classcommon(CuTest *tc);
+
+void test_cil_copy_sid(CuTest *);
+void test_cil_copy_node_helper_sid(CuTest *tc);
+void test_cil_copy_node_helper_sid_merge(CuTest *tc);
+
+void test_cil_copy_sidcontext(CuTest *);
+void test_cil_copy_node_helper_sidcontext(CuTest *tc);
+
+void test_cil_copy_user(CuTest *);
+void test_cil_copy_node_helper_user(CuTest *tc);
+void test_cil_copy_node_helper_user_merge(CuTest *tc);
+
+void test_cil_copy_role(CuTest *);
+void test_cil_copy_node_helper_role(CuTest *tc);
+void test_cil_copy_node_helper_role_merge(CuTest *tc);
+
+void test_cil_copy_userrole(CuTest *);
+void test_cil_copy_node_helper_userrole(CuTest *tc);
+
+void test_cil_copy_type(CuTest *);
+void test_cil_copy_node_helper_type(CuTest *tc);
+void test_cil_copy_node_helper_type_merge(CuTest *tc);
+
+void test_cil_copy_typeattribute(CuTest *);
+void test_cil_copy_node_helper_typeattribute(CuTest *tc);
+void test_cil_copy_node_helper_typeattribute_merge(CuTest *tc);
+
+void test_cil_copy_typealias(CuTest *);
+void test_cil_copy_node_helper_typealias(CuTest *tc);
+void test_cil_copy_node_helper_typealias_dup_neg(CuTest *tc);
+
+void test_cil_copy_bool(CuTest *);
+void test_cil_copy_node_helper_bool(CuTest *tc);
+void test_cil_copy_node_helper_bool_dup_neg(CuTest *tc);
+
+void test_cil_copy_avrule(CuTest *);
+void test_cil_copy_node_helper_avrule(CuTest *tc);
+
+void test_cil_copy_type_rule(CuTest *);
+void test_cil_copy_node_helper_type_rule(CuTest *tc);
+
+void test_cil_copy_sens(CuTest *);
+void test_cil_copy_node_helper_sens(CuTest *tc);
+void test_cil_copy_node_helper_sens_merge(CuTest *tc);
+
+void test_cil_copy_sensalias(CuTest *);
+void test_cil_copy_node_helper_sensalias(CuTest *tc);
+void test_cil_copy_node_helper_sensalias_dup_neg(CuTest *tc);
+
+void test_cil_copy_cat(CuTest *);
+void test_cil_copy_node_helper_cat(CuTest *tc);
+void test_cil_copy_node_helper_cat_merge(CuTest *tc);
+
+void test_cil_copy_catalias(CuTest *);
+void test_cil_copy_node_helper_catalias(CuTest *tc);
+void test_cil_copy_node_helper_catalias_dup_neg(CuTest *tc);
+
+void test_cil_copy_senscat(CuTest *);
+void test_cil_copy_node_helper_senscat(CuTest *tc);
+
+void test_cil_copy_catorder(CuTest *);
+void test_cil_copy_node_helper_catorder(CuTest *tc);
+
+void test_cil_copy_dominance(CuTest *);
+void test_cil_copy_node_helper_dominance(CuTest *tc);
+
+void test_cil_copy_level(CuTest *);
+void test_cil_copy_node_helper_level(CuTest *tc);
+void test_cil_copy_node_helper_level_dup_neg(CuTest *tc);
+
+void test_cil_copy_fill_level(CuTest *);
+
+void test_cil_copy_context(CuTest *);
+void test_cil_copy_node_helper_context(CuTest *tc);
+void test_cil_copy_node_helper_context_dup_neg(CuTest *tc);
+
+void test_cil_copy_netifcon(CuTest *);
+void test_cil_copy_netifcon_nested(CuTest *);
+void test_cil_copy_node_helper_netifcon(CuTest *tc);
+void test_cil_copy_node_helper_netifcon_merge(CuTest *tc);
+
+void test_cil_copy_fill_context(CuTest *);
+void test_cil_copy_fill_context_anonrange(CuTest *);
+
+void test_cil_copy_call(CuTest *);
+void test_cil_copy_node_helper_call(CuTest *tc);
+
+void test_cil_copy_optional(CuTest *);
+void test_cil_copy_node_helper_optional(CuTest *tc);
+void test_cil_copy_node_helper_optional_merge(CuTest *tc);
+
+void test_cil_copy_nodecon(CuTest *);
+void test_cil_copy_nodecon_anon(CuTest *);
+
+void test_cil_copy_fill_ipaddr(CuTest *);
+
+void test_cil_copy_ipaddr(CuTest *);
+void test_cil_copy_node_helper_ipaddr(CuTest *tc);
+void test_cil_copy_node_helper_ipaddr_dup_neg(CuTest *tc);
+
+void test_cil_copy_conditional(CuTest *);
+
+void test_cil_copy_boolif(CuTest *);
+void test_cil_copy_node_helper_boolif(CuTest *tc);
+
+void test_cil_copy_constrain(CuTest *);
+void test_cil_copy_node_helper_mlsconstrain(CuTest *tc);
+
+void test_cil_copy_ast(CuTest *);
+void test_cil_copy_ast_neg(CuTest *);
+
+void test_cil_copy_node_helper_orignull_neg(CuTest *tc);
+void test_cil_copy_node_helper_extraargsnull_neg(CuTest *tc);
+
+void test_cil_copy_data_helper(CuTest *tc);
+void test_cil_copy_data_helper_getparentsymtab_neg(CuTest *tc);
+void test_cil_copy_data_helper_duplicatedb_neg(CuTest *tc);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_fqn.c b/libsepol/cil/test/unit/test_cil_fqn.c
new file mode 100644
index 0000000..4304fc1
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_fqn.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_fqn.h"
+#include "../../src/cil_build_ast.h"
+
+void test_cil_qualify_name(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "sid", "test", "con", NULL};
+
+ struct cil_tree *tree;
+ gen_test_tree(&tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, tree->root, test_db->ast->root);
+
+ int rc = cil_fqn_qualify(test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_qualify_name_cil_flavor(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "inherits", "file",
+ "(", "open", ")", ")", NULL};
+
+ struct cil_tree *tree;
+ gen_test_tree(&tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, tree->root, test_db->ast->root);
+
+ int rc = cil_fqn_qualify(test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_fqn.h b/libsepol/cil/test/unit/test_cil_fqn.h
new file mode 100644
index 0000000..93f0ffd
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_fqn.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_FQN_H_
+#define TEST_CIL_FQN_H_
+
+#include "CuTest.h"
+
+void test_cil_qualify_name(CuTest *);
+void test_cil_qualify_name_cil_flavor(CuTest *tc);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_lexer.c b/libsepol/cil/test/unit/test_cil_lexer.c
new file mode 100644
index 0000000..011afef
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_lexer.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_lexer.h"
+
+#include "../../src/cil_lexer.h"
+
+void test_cil_lexer_setup(CuTest *tc) {
+ char *test_str = "(test \"qstring\");comment\n";
+ uint32_t str_size = strlen(test_str);
+ char *buffer = malloc(str_size + 2);
+
+ memset(buffer+str_size, 0, 2);
+ strncpy(buffer, test_str, str_size);
+
+ int rc = cil_lexer_setup(buffer, str_size + 2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ free(buffer);
+}
+
+void test_cil_lexer_next(CuTest *tc) {
+ char *test_str = "(test \"qstring\") ;comment\n";
+ uint32_t str_size = strlen(test_str);
+ char *buffer = malloc(str_size + 2);
+
+ memset(buffer+str_size, 0, 2);
+ strcpy(buffer, test_str);
+
+ cil_lexer_setup(buffer, str_size + 2);
+
+ struct token test_tok;
+
+ int rc = cil_lexer_next(&test_tok);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ CuAssertIntEquals(tc, OPAREN, test_tok.type);
+ CuAssertStrEquals(tc, "(", test_tok.value);
+ CuAssertIntEquals(tc, 1, test_tok.line);
+
+ rc = cil_lexer_next(&test_tok);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ CuAssertIntEquals(tc, SYMBOL, test_tok.type);
+ CuAssertStrEquals(tc, "test", test_tok.value);
+ CuAssertIntEquals(tc, 1, test_tok.line);
+
+ rc = cil_lexer_next(&test_tok);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ CuAssertIntEquals(tc, QSTRING, test_tok.type);
+ CuAssertStrEquals(tc, "\"qstring\"", test_tok.value);
+ CuAssertIntEquals(tc, 1, test_tok.line);
+
+ rc = cil_lexer_next(&test_tok);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ CuAssertIntEquals(tc, CPAREN, test_tok.type);
+ CuAssertStrEquals(tc, ")", test_tok.value);
+ CuAssertIntEquals(tc, 1, test_tok.line);
+
+ rc = cil_lexer_next(&test_tok);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+
+ CuAssertIntEquals(tc, COMMENT, test_tok.type);
+ CuAssertStrEquals(tc, ";comment", test_tok.value);
+ CuAssertIntEquals(tc, 1, test_tok.line);
+
+ free(buffer);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_lexer.h b/libsepol/cil/test/unit/test_cil_lexer.h
new file mode 100644
index 0000000..78a4609
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_lexer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_LEXER_H_
+#define TEST_CIL_LEXER_H_
+
+#include "CuTest.h"
+
+void test_cil_lexer_setup(CuTest *);
+void test_cil_lexer_next(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_list.c b/libsepol/cil/test/unit/test_cil_list.c
new file mode 100644
index 0000000..b7a63af
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_list.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_internal.h"
+#include "../../src/cil_build_ast.h"
+
+void test_cil_list_init(CuTest *tc) {
+ struct cil_avrule *test_avrule = malloc(sizeof(*test_avrule));
+
+ cil_classpermset_init(&test_avrule->classpermset);
+ cil_permset_init(&test_avrule->classpermset->permset);
+
+ cil_list_init(&test_avrule->classpermset->permset->perms_list_str);
+ CuAssertPtrNotNull(tc, test_avrule->classpermset->permset->perms_list_str);
+
+ cil_destroy_avrule(test_avrule);
+}
+
+void test_cil_list_append_item(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_append_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_append_item_append(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_append_item(test_class_list, test_new_item);
+
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+
+ int rc2 = cil_list_append_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_list_append_item_append_extra(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", "process", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_append_item(test_class_list, test_new_item);
+
+ cil_list_item_init(&test_new_item);
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+
+ int rc2 = cil_list_append_item(test_class_list, test_new_item);
+
+ cil_list_item_init(&test_new_item);
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next->next;
+
+ int rc3 = cil_list_append_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_list_append_item_listnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list = NULL;
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_append_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_append_item_itemnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item = NULL;
+
+ int rc = cil_list_append_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_prepend_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_prepend_item_prepend(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_prepend_item(test_class_list, test_new_item);
+
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_list_prepend_item_prepend_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", "process", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ struct cil_list_item *test_new_item_next;
+ cil_list_item_init(&test_new_item_next);
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head->next;
+ test_new_item->next = test_new_item_next;
+
+ int rc = cil_list_prepend_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item_listnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list = NULL;
+
+ struct cil_list_item *test_new_item;
+ cil_list_item_init(&test_new_item);
+
+ test_new_item->flavor = CIL_CLASS;
+ test_new_item->data = test_tree->root->cl_head->cl_head->next->cl_head;
+
+ int rc = cil_list_prepend_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_list_prepend_item_itemnull_neg(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "dir", ")", "(", "create", "relabelto", ")", "(", "eq", "12", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ struct cil_list *test_class_list;
+ cil_list_init(&test_class_list);
+
+ struct cil_list_item *test_new_item = NULL;
+
+ int rc = cil_list_prepend_item(test_class_list, test_new_item);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_list.h b/libsepol/cil/test/unit/test_cil_list.h
new file mode 100644
index 0000000..e627683
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_list.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_LIST_H_
+#define TEST_CIL_LIST_H_
+
+#include "CuTest.h"
+
+void test_cil_list_item_init(CuTest *);
+void test_cil_list_append_item(CuTest *);
+void test_cil_list_append_item_append(CuTest *);
+void test_cil_list_append_item_append_extra(CuTest *);
+void test_cil_list_append_item_listnull_neg(CuTest *);
+void test_cil_list_append_item_itemnull_neg(CuTest *);
+void test_cil_list_prepend_item_prepend(CuTest *);
+void test_cil_list_prepend_item_prepend_neg(CuTest *);
+void test_cil_list_prepend_item_listnull_neg(CuTest *);
+void test_cil_list_prepend_item_itemnull_neg(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_parser.c b/libsepol/cil/test/unit/test_cil_parser.c
new file mode 100644
index 0000000..43dc305
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_parser.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_parser.h"
+
+#include "../../src/cil_parser.h"
+#include "../../src/cil_internal.h"
+
+// TODO rewrite to use the gen_tree function
+void test_cil_parser(CuTest *tc) {
+ int rc = 0;
+ struct cil_file_data *data;
+
+ struct cil_tree *test_parse_root;
+ cil_tree_init(&test_parse_root);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ set_cil_file_data(&data);
+
+ rc = cil_parser("policy.cil", data->buffer, data->file_size + 2, &test_parse_root);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_parse_root);
+ // TODO add checking of the parse tree that is returned
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_parser.h b/libsepol/cil/test/unit/test_cil_parser.h
new file mode 100644
index 0000000..2cb280d
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_parser.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_PARSER_H_
+#define TEST_CIL_PARSER_H_
+
+#include "CuTest.h"
+
+void test_cil_parser(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_post.c b/libsepol/cil/test/unit/test_cil_post.c
new file mode 100644
index 0000000..8bb7e76
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_post.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+#include "test_cil_post.h"
+
+#include "../../src/cil_post.h"
+#include "../../src/cil_internal.h"
+
+void test_cil_post_filecon_compare_meta_a_not_b(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = "ba.r";
+ afilecon->path_str = "foo";
+
+ bfilecon->root_str = "barr";
+ bfilecon->path_str = "foo";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_meta_b_not_a(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = "bar";
+ afilecon->path_str = "foo";
+
+ bfilecon->root_str = "ba.rr";
+ bfilecon->path_str = "foo";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = ".\\$";
+ afilecon->path_str = ".$({";
+
+ bfilecon->root_str = ".?";
+ bfilecon->path_str = ".";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_type_atype_greater_btype(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = ".\\$";
+ afilecon->path_str = ".$({";
+ afilecon->type = CIL_FILECON_CHAR;
+
+ bfilecon->root_str = ".\\$";
+ bfilecon->path_str = ".$({";
+ bfilecon->type = CIL_FILECON_DIR;
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_type_btype_greater_atype(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = ".\\$";
+ afilecon->path_str = ".$({";
+ afilecon->type = CIL_FILECON_DIR;
+
+ bfilecon->root_str = ".\\$";
+ bfilecon->path_str = ".$({";
+ bfilecon->type = CIL_FILECON_CHAR;
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = ".";
+ afilecon->path_str = ".";
+
+ bfilecon->root_str = ".*+|[({";
+ bfilecon->path_str = ".";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_stemlen_a_greater_b(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = "bar";
+ afilecon->path_str = "foo";
+
+ bfilecon->root_str = "barr";
+ bfilecon->path_str = "foo";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_filecon_compare_stemlen_b_greater_a(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = "barre";
+ afilecon->path_str = "foo";
+
+ bfilecon->root_str = "barr";
+ bfilecon->path_str = "foo";
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_filecon_compare_equal(CuTest *tc) {
+ struct cil_filecon *afilecon;
+ cil_filecon_init(&afilecon);
+
+ struct cil_filecon *bfilecon;
+ cil_filecon_init(&bfilecon);
+
+ afilecon->root_str = ".\\$";
+ afilecon->path_str = ".$({";
+ afilecon->type = CIL_FILECON_DIR;
+
+ bfilecon->root_str = ".\\$";
+ bfilecon->path_str = ".$({";
+ bfilecon->type = CIL_FILECON_DIR;
+
+
+ int rc = cil_post_filecon_compare(&afilecon, &bfilecon);
+ CuAssertIntEquals(tc, 0, rc);
+}
+
+void test_cil_post_portcon_compare_atotal_greater_btotal(CuTest *tc) {
+ struct cil_portcon *aportcon;
+ cil_portcon_init(&aportcon);
+
+ struct cil_portcon *bportcon;
+ cil_portcon_init(&bportcon);
+
+ aportcon->port_low = 15;
+ aportcon->port_high = 30;
+
+ bportcon->port_low = 10;
+ bportcon->port_high = 11;
+
+ int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_portcon_compare_btotal_greater_atotal(CuTest *tc) {
+ struct cil_portcon *aportcon;
+ cil_portcon_init(&aportcon);
+
+ struct cil_portcon *bportcon;
+ cil_portcon_init(&bportcon);
+
+ aportcon->port_low = 5;
+ aportcon->port_high = 5;
+
+ bportcon->port_low = 11;
+ bportcon->port_high = 20;
+
+ int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_portcon_compare_aportlow_greater_bportlow(CuTest *tc) {
+ struct cil_portcon *aportcon;
+ cil_portcon_init(&aportcon);
+
+ struct cil_portcon *bportcon;
+ cil_portcon_init(&bportcon);
+
+ aportcon->port_low = 30;
+ aportcon->port_high = 33;
+
+ bportcon->port_low = 17;
+ bportcon->port_high = 20;
+
+ int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_portcon_compare_bportlow_greater_aportlow(CuTest *tc) {
+ struct cil_portcon *aportcon;
+ cil_portcon_init(&aportcon);
+
+ struct cil_portcon *bportcon;
+ cil_portcon_init(&bportcon);
+
+ aportcon->port_low = 5;
+ aportcon->port_high = 8;
+
+ bportcon->port_low = 17;
+ bportcon->port_high = 20;
+
+ int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_portcon_compare_equal(CuTest *tc) {
+ struct cil_portcon *aportcon;
+ cil_portcon_init(&aportcon);
+
+ struct cil_portcon *bportcon;
+ cil_portcon_init(&bportcon);
+
+ aportcon->port_low = 17;
+ aportcon->port_high = 20;
+
+ bportcon->port_low = 17;
+ bportcon->port_high = 20;
+
+ int rc = cil_post_portcon_compare(&aportcon, &bportcon);
+ CuAssertTrue(tc, rc == 0);
+}
+
+void test_cil_post_genfscon_compare_atypestr_greater_btypestr(CuTest *tc) {
+ struct cil_genfscon *agenfscon;
+ cil_genfscon_init(&agenfscon);
+ agenfscon->fs_str = "aaaa";
+
+ struct cil_genfscon *bgenfscon;
+ cil_genfscon_init(&bgenfscon);
+ bgenfscon->fs_str = "bbbb";
+
+ int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_genfscon_compare_btypestr_greater_atypestr(CuTest *tc) {
+ struct cil_genfscon *agenfscon;
+ cil_genfscon_init(&agenfscon);
+ agenfscon->fs_str = "bbbb";
+
+ struct cil_genfscon *bgenfscon;
+ cil_genfscon_init(&bgenfscon);
+ bgenfscon->fs_str = "aaaa";
+
+ int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_genfscon_compare_apathstr_greater_bpathstr(CuTest *tc) {
+ struct cil_genfscon *agenfscon;
+ cil_genfscon_init(&agenfscon);
+ agenfscon->fs_str = "aaaa";
+ agenfscon->path_str = "ff";
+
+ struct cil_genfscon *bgenfscon;
+ cil_genfscon_init(&bgenfscon);
+ bgenfscon->fs_str = "aaaa";
+ bgenfscon->path_str = "gg";
+
+ int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_genfscon_compare_bpathstr_greater_apathstr(CuTest *tc) {
+ struct cil_genfscon *agenfscon;
+ cil_genfscon_init(&agenfscon);
+ agenfscon->fs_str = "bbbb";
+ agenfscon->path_str = "cccc";
+
+ struct cil_genfscon *bgenfscon;
+ cil_genfscon_init(&bgenfscon);
+ bgenfscon->fs_str = "bbbb";
+ bgenfscon->path_str = "aaaa";
+
+ int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_genfscon_compare_equal(CuTest *tc) {
+ struct cil_genfscon *agenfscon;
+ cil_genfscon_init(&agenfscon);
+ agenfscon->fs_str = "bbbb";
+ agenfscon->path_str = "cccc";
+
+ struct cil_genfscon *bgenfscon;
+ cil_genfscon_init(&bgenfscon);
+ bgenfscon->fs_str = "bbbb";
+ bgenfscon->path_str = "cccc";
+
+ int rc = cil_post_genfscon_compare(&agenfscon, &bgenfscon);
+ CuAssertIntEquals(tc, 0, rc);
+}
+
+void test_cil_post_netifcon_compare_a_greater_b(CuTest *tc) {
+ struct cil_netifcon *anetifcon;
+ cil_netifcon_init(&anetifcon);
+ anetifcon->interface_str = "aaa";
+
+ struct cil_netifcon *bnetifcon;
+ cil_netifcon_init(&bnetifcon);
+ bnetifcon->interface_str = "bbb";
+
+ int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_netifcon_compare_b_greater_a(CuTest *tc) {
+ struct cil_netifcon *anetifcon;
+ cil_netifcon_init(&anetifcon);
+ anetifcon->interface_str = "bbb";
+
+ struct cil_netifcon *bnetifcon;
+ cil_netifcon_init(&bnetifcon);
+ bnetifcon->interface_str = "aaa";
+
+ int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_netifcon_compare_equal(CuTest *tc) {
+ struct cil_netifcon *anetifcon;
+ cil_netifcon_init(&anetifcon);
+ anetifcon->interface_str = "aaa";
+
+ struct cil_netifcon *bnetifcon;
+ cil_netifcon_init(&bnetifcon);
+ bnetifcon->interface_str = "aaa";
+
+ int rc = cil_post_netifcon_compare(&anetifcon, &bnetifcon);
+ CuAssertTrue(tc, rc == 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_bipv6(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 103;
+ anodecon->mask->ip.v4.s_addr = 100;
+ anodecon->addr->family = AF_INET;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET6;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_bipv4(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 103;
+ anodecon->mask->ip.v4.s_addr = 100;
+ anodecon->addr->family = AF_INET6;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 103;
+ anodecon->mask->ip.v4.s_addr = 100;
+ anodecon->addr->family = AF_INET;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv4_lessthan_bipv4(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 99;
+ anodecon->mask->ip.v4.s_addr = 100;
+ anodecon->addr->family = AF_INET;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 103;
+ anodecon->mask->ip.v4.s_addr = 101;
+ anodecon->addr->family = AF_INET;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v4.s_addr = 99;
+ anodecon->mask->ip.v4.s_addr = 99;
+ anodecon->addr->family = AF_INET;
+
+ bnodecon->addr->ip.v4.s_addr = 100;
+ bnodecon->mask->ip.v4.s_addr = 100;
+ bnodecon->addr->family = AF_INET;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v6.s6_addr[0] = '5';
+ anodecon->mask->ip.v6.s6_addr[0] = '9';
+ anodecon->addr->family = AF_INET6;
+
+ bnodecon->addr->ip.v6.s6_addr[0] = '3';
+ bnodecon->mask->ip.v6.s6_addr[0] = '9';
+ bnodecon->addr->family = AF_INET6;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_nodecon_compare_aipv6_lessthan_bipv6(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v6.s6_addr[0] = '3';
+ anodecon->mask->ip.v6.s6_addr[0] = '1';
+ anodecon->addr->family = AF_INET6;
+
+ bnodecon->addr->ip.v6.s6_addr[0] = '5';
+ bnodecon->mask->ip.v6.s6_addr[0] = '1';
+ bnodecon->addr->family = AF_INET6;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v6.s6_addr[0] = '1';
+ anodecon->mask->ip.v6.s6_addr[0] = '4';
+ anodecon->addr->family = AF_INET6;
+
+ bnodecon->addr->ip.v6.s6_addr[0] = '1';
+ bnodecon->mask->ip.v6.s6_addr[0] = '3';
+ bnodecon->addr->family = AF_INET6;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6(CuTest *tc) {
+ struct cil_nodecon *anodecon;
+ cil_nodecon_init(&anodecon);
+ cil_ipaddr_init(&anodecon->addr);
+ cil_ipaddr_init(&anodecon->mask);
+
+ struct cil_nodecon *bnodecon;
+ cil_nodecon_init(&bnodecon);
+ cil_ipaddr_init(&bnodecon->addr);
+ cil_ipaddr_init(&bnodecon->mask);
+
+ anodecon->addr->ip.v6.s6_addr[0] = '5';
+ anodecon->mask->ip.v6.s6_addr[0] = '1';
+ anodecon->addr->family = AF_INET6;
+
+ bnodecon->addr->ip.v6.s6_addr[0] = '5';
+ bnodecon->mask->ip.v6.s6_addr[0] = '6';
+ bnodecon->addr->family = AF_INET6;
+
+ int rc = cil_post_nodecon_compare(&anodecon, &bnodecon);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_type_a_greater_b(CuTest *tc) {
+ struct cil_fsuse *afsuse;
+ cil_fsuse_init(&afsuse);
+ afsuse->type = CIL_FSUSE_XATTR;
+
+ struct cil_fsuse *bfsuse;
+ cil_fsuse_init(&bfsuse);
+ bfsuse->type = CIL_FSUSE_TASK;
+
+ int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_fsuse_compare_type_b_greater_a(CuTest *tc) {
+ struct cil_fsuse *afsuse;
+ cil_fsuse_init(&afsuse);
+ afsuse->type = CIL_FSUSE_TASK;
+
+ struct cil_fsuse *bfsuse;
+ cil_fsuse_init(&bfsuse);
+ bfsuse->type = CIL_FSUSE_XATTR;
+
+ int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_fsstr_a_greater_b(CuTest *tc) {
+ struct cil_fsuse *afsuse;
+ cil_fsuse_init(&afsuse);
+ afsuse->type = CIL_FSUSE_XATTR;
+ afsuse->fs_str = "aaa";
+
+ struct cil_fsuse *bfsuse;
+ cil_fsuse_init(&bfsuse);
+ bfsuse->type = CIL_FSUSE_XATTR;
+ bfsuse->fs_str = "bbb";
+
+ int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+ CuAssertTrue(tc, rc < 0);
+}
+
+void test_cil_post_fsuse_compare_fsstr_b_greater_a(CuTest *tc) {
+ struct cil_fsuse *afsuse;
+ cil_fsuse_init(&afsuse);
+ afsuse->type = CIL_FSUSE_XATTR;
+ afsuse->fs_str = "bbb";
+
+ struct cil_fsuse *bfsuse;
+ cil_fsuse_init(&bfsuse);
+ bfsuse->type = CIL_FSUSE_XATTR;
+ bfsuse->fs_str = "aaa";
+
+ int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+ CuAssertTrue(tc, rc > 0);
+}
+
+void test_cil_post_fsuse_compare_equal(CuTest *tc) {
+ struct cil_fsuse *afsuse;
+ cil_fsuse_init(&afsuse);
+ afsuse->type = CIL_FSUSE_XATTR;
+ afsuse->fs_str = "foo";
+
+ struct cil_fsuse *bfsuse;
+ cil_fsuse_init(&bfsuse);
+ bfsuse->type = CIL_FSUSE_XATTR;
+ bfsuse->fs_str = "foo";
+
+ int rc = cil_post_fsuse_compare(&afsuse, &bfsuse);
+ CuAssertTrue(tc, rc == 0);
+}
+
+
+
diff --git a/libsepol/cil/test/unit/test_cil_post.h b/libsepol/cil/test/unit/test_cil_post.h
new file mode 100644
index 0000000..b3c16a3
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_post.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_POLICY_H_
+#define TEST_CIL_POLICY_H_
+
+#include "CuTest.h"
+
+void test_cil_post_filecon_compare_meta_a_not_b(CuTest *tc);
+void test_cil_post_filecon_compare_meta_b_not_a(CuTest *tc);
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_a_greater_b(CuTest *tc);
+void test_cil_post_filecon_compare_meta_a_and_b_strlen_b_greater_a(CuTest *tc);
+void test_cil_post_filecon_compare_type_atype_greater_btype(CuTest *tc);
+void test_cil_post_filecon_compare_type_btype_greater_atype(CuTest *tc);
+void test_cil_post_filecon_compare_stemlen_a_greater_b(CuTest *tc);
+void test_cil_post_filecon_compare_stemlen_b_greater_a(CuTest *tc);
+void test_cil_post_filecon_compare_equal(CuTest *tc);
+
+void test_cil_post_portcon_compare_atotal_greater_btotal(CuTest *tc);
+void test_cil_post_portcon_compare_btotal_greater_atotal(CuTest *tc);
+void test_cil_post_portcon_compare_aportlow_greater_bportlow(CuTest *tc);
+void test_cil_post_portcon_compare_bportlow_greater_aportlow(CuTest *tc);
+void test_cil_post_portcon_compare_equal(CuTest *tc);
+
+void test_cil_post_genfscon_compare_atypestr_greater_btypestr(CuTest *tc);
+void test_cil_post_genfscon_compare_btypestr_greater_atypestr(CuTest *tc);
+void test_cil_post_genfscon_compare_apathstr_greater_bpathstr(CuTest *tc);
+void test_cil_post_genfscon_compare_bpathstr_greater_apathstr(CuTest *tc);
+void test_cil_post_genfscon_compare_equal(CuTest *tc);
+
+void test_cil_post_netifcon_compare_a_greater_b(CuTest *tc);
+void test_cil_post_netifcon_compare_b_greater_a(CuTest *tc);
+void test_cil_post_netifcon_compare_equal(CuTest *tc);
+
+void test_cil_post_nodecon_compare_aipv4_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv4_greaterthan_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv4_lessthan_bipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv4_greaterthan_bmaskipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv4_lessthan_bmaskipv4(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_greaterthan_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_aipv6_lessthan_bipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv6_greaterthan_bmaskipv6(CuTest *tc);
+void test_cil_post_nodecon_compare_amaskipv6_lessthan_bmaskipv6(CuTest *tc);
+
+void test_cil_post_fsuse_compare_type_a_greater_b(CuTest *tc);
+void test_cil_post_fsuse_compare_type_b_greater_a(CuTest *tc);
+void test_cil_post_fsuse_compare_fsstr_a_greater_b(CuTest *tc);
+void test_cil_post_fsuse_compare_fsstr_b_greater_a(CuTest *tc);
+void test_cil_post_fsuse_compare_equal(CuTest *tc);
+
+#endif
+
diff --git a/libsepol/cil/test/unit/test_cil_resolve_ast.c b/libsepol/cil/test/unit/test_cil_resolve_ast.c
new file mode 100644
index 0000000..1540c2b
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_resolve_ast.c
@@ -0,0 +1,11319 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "CilTest.h"
+
+#include "../../src/cil_build_ast.h"
+#include "../../src/cil_resolve_ast.h"
+#include "../../src/cil_verify.h"
+#include "../../src/cil_internal.h"
+
+/* this all needs to be moved to a private header file */
+int __cil_resolve_ast_node_helper(struct cil_tree_node *, uint32_t *, void *);
+int __cil_disable_children_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *);
+
+struct cil_args_resolve {
+ struct cil_db *db;
+ enum cil_pass pass;
+ uint32_t *changed;
+ struct cil_tree_node *callstack;
+ struct cil_tree_node *optstack;
+ struct cil_tree_node *macro;
+};
+
+struct cil_args_resolve *gen_resolve_args(struct cil_db *db, enum cil_pass pass, uint32_t *changed, struct cil_tree_node *calls, struct cil_tree_node *opts, struct cil_tree_node *macro)
+{
+ struct cil_args_resolve *args = cil_malloc(sizeof(*args));
+ args->db = db;
+ args->pass = pass;
+ args->changed = changed;
+ args->callstack = calls;
+ args->optstack = opts;
+ args->macro = macro;
+
+ return args;
+}
+
+void test_cil_resolve_name(CuTest *tc) {
+ char *line[] = { "(", "block", "foo",
+ "(", "typealias", "test", "type_t", ")",
+ "(", "type", "test", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_curr = test_db->ast->root->cl_head->cl_head;
+ struct cil_typealias *test_alias = (struct cil_typealias*)test_curr->data;
+ struct cil_tree_node *type_node = NULL;
+
+ int rc = cil_resolve_name(test_curr, test_alias->type_str, CIL_SYM_TYPES, args, &type_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_invalid_type_neg(CuTest *tc) {
+ char *line[] = { "(", "block", "foo",
+ "(", "typealias", "foo.test2", "type_t", ")",
+ "(", "type", "test", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_curr = test_db->ast->root->cl_head->cl_head;
+ struct cil_typealias *test_alias = (struct cil_typealias*)test_curr->data;
+ struct cil_tree_node *type_node = NULL;
+
+ int rc = cil_resolve_name(test_curr, test_alias->type_str, CIL_SYM_TYPES, args, &type_node);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_curr_null_neg(CuTest *tc) {
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_db->ast->root = NULL;
+
+ int rc = cil_resolve_ast(test_db, test_db->ast->root);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+
+/*
+ cil_resolve test cases
+*/
+
+void test_cil_resolve_roleallow(CuTest *tc) {
+ char *line[] = {"(", "role", "foo", ")", \
+ "(", "role", "bar", ")", \
+ "(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roleallow_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "bar", ")", \
+ "(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc1=cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ rc1 = rc1;
+
+ int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roleallow_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo", ")", \
+ "(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roleallow(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+ "(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "(", "file", "(", "open", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classmapping_anon_inmacro(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ args->pass = CIL_PASS_CALL1;
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next;
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_classmapping_anon_inmacro_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "(", "DNE", "(", "open", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ args->pass = CIL_PASS_CALL1;
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next;
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_classmapping_named(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+ "(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classmapping_named_classmapname_neg(CuTest *tc) {
+ char *line[] = {"(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+ "(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon_classmapname_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+ "(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "dne", "read", "(", "file", "(", "open", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classmapping_anon_permset_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+ "(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "(", "dne", "(", "open", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classmapping(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rolebounds(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "role", "role2", ")",
+ "(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rolebounds_exists_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "role", "role2", ")",
+ "(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+ int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_rolebounds_role1_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "role", "role2", ")",
+ "(", "rolebounds", "role_DNE", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rolebounds_role2_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "role", "role2", ")",
+ "(", "rolebounds", "role1", "role_DNE", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rolebounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_sensalias(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sensalias_sensdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_sensalias(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catalias(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_catalias(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catalias_catdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_catalias(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catorder(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c3", ")",
+ "(", "categoryorder", "(", "c0", "c3", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ int rc2 = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_catorder_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c3", ")",
+ "(", "categoryorder", "(", "c5", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+ int rc2 = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_dominance_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s6", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_dominance(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_cat_list(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_list *test_cat_list;
+ cil_list_init(&test_cat_list);
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_cat_list_catlistnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_list *test_cat_list;
+ cil_list_init(&test_cat_list);
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+ test_catset->cat_list_str = NULL;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_rescatlistnull_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_list *test_cat_list = NULL;
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_catrange(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+ "(", "categoryset", "somecats", "(", "c0", "(", "c1", "c2", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ struct cil_list *test_cat_list;
+ cil_list_init(&test_cat_list);
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_cat_list_catrange_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+ "(", "categoryset", "somecats", "(", "c0", "(", "c2", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_list *test_cat_list;
+ cil_list_init(&test_cat_list);
+
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MLS;
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_cat_list_catname_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c5", ")",
+ "(", "category", "c6", ")",
+ "(", "category", "c7", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+ "(", "categoryset", "somecats", "(", "c0", "(", "c1", "c2", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MLS;
+ struct cil_list *test_cat_list;
+ cil_list_init(&test_cat_list);
+
+ struct cil_catset *test_catset = (struct cil_catset*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_cat_list(test_db->ast->root->cl_head->next->next->next->next, test_catset->cat_list_str, test_cat_list, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catset(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, test_catset, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catset_catlist_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", "c4", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, test_catset, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catrange(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_catrange_catloworder_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ test_db->catorder->head = test_db->catorder->head->next;
+ test_db->catorder->head->next = NULL;
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_catrange_cathighorder_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c255", "c0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_catrange_cat1_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c12", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_catrange_cat2_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c0", "c23", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_catrange(test_db->ast->root->cl_head->next->next->next, (struct cil_catrange*)test_db->ast->root->cl_head->next->next->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_catrange_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "category", "c500", ")",
+ "(", "categoryorder", "(", "c0", "c255", "c500", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "(", "c255", "c5", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_senscat_catsetname(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "category", "c500", ")",
+ "(", "categoryset", "foo", "(", "c0", "c255", "c500", ")", ")",
+ "(", "categoryorder", "(", "c0", "c255", "c500", ")", ")",
+ "(", "sensitivitycategory", "s1", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_catset *test_catset = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+ cil_resolve_catset(test_db->ast->root->cl_head->next->next->next->next->next, test_catset, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_catsetname_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "category", "c500", ")",
+ "(", "sensitivitycategory", "s1", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_sublist(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "(", "c1", "c255", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_senscat_missingsens_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_category_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c5", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_senscat_currrangecat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "(", "c1", "c255", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MISC2;
+
+ int rc = cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_level_catlist(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "categoryorder", "(", "c0", "c1", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", "c1", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", "c1", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", "c1", ")", ")", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level_catset(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "cats", "(", "c0", "c1", "c2", ")", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "cats", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "cats", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "cats", ")", ")", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ struct cil_catset *cs = (struct cil_catset *)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MLS;
+
+ cil_resolve_catset(test_db->ast->root->cl_head->next->next->next, cs, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_level_catset_name_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "cats", "(", "c0", "c1", "c2", ")", ")",
+ "(", "categoryorder", "(", "c0", "c1", "c2", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "cats", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "dne", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_level_sens_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s1", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s1", "(", "c0", ")", ")", ")",
+ "(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc2);
+}
+
+void test_cil_resolve_level_cat_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+ args->pass = CIL_PASS_MISC3;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc2);
+}
+
+void test_cil_resolve_level_senscat_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+ args->pass = CIL_PASS_MISC3;
+ int rc = cil_resolve_level(level, (struct cil_level*)level->data, args);
+ int rc2 = cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc2);
+}
+
+void test_cil_resolve_levelrange_namedlvl(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "range", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_levelrange_namedlvl_low_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "range", "(", "DNE", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_namedlvl_high_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "range", "(", "low", "DNE", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->next->next->data;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl_low_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "DNE", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_levelrange_anonlvl_high_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "dne", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ struct cil_levelrange *lvlrange = (struct cil_levelrange *)test_db->ast->root->cl_head->next->next->next->data;
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_levelrange(test_db->ast->root->cl_head->next->next->next, lvlrange, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_constrain_class_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "foo", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain_perm_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_constrain_perm_resolve_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "file", "(", "foo", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_constrain(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_context_macro(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "range", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head->data;
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_context_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "range", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "DNE", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head->data;
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_context_namedrange(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "range", "(", "low", "high", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "range", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_context_namedrange_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "range", "(", "low", "high", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "DNE", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_user_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_role_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_type_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_context_anon_level_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "DNE", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_context *test_context = (struct cil_context*)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data;
+
+ int rc = cil_resolve_context(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, test_context, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "type", "bar_t", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roletransition_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "bar_t", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletransition_resultdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "type", "bar_t", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletransition(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_type_in_multiple_attrs(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "typeattribute", "attrs2", ")",
+ "(", "type", "type_t", ")",
+ "(", "typeattributeset", "attrs2", "type_t", ")",
+ "(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next->next, args);
+ int rc2 = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_typeattributeset_multiple_excludes_with_not(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "typeattribute", "attrs2", ")",
+ "(", "type", "type_t", ")",
+ "(", "type", "type_b", ")",
+ "(", "type", "type_a", ")",
+ "(", "typeattributeset", "attrs", "(", "and", "type_a", "type_b", ")", ")",
+ "(", "typeattributeset", "attrs2", "(", "not", "attrs", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_multiple_types_with_and(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "type", "type_t", ")",
+ "(", "type", "type_tt", ")",
+ "(", "typeattributeset", "attrs", "(", "and", "type_t", "type_tt", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_using_attr(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "typeattribute", "attr_a", ")",
+ "(", "typeattributeset", "attrs", "attr_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_name_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_t", ")",
+ "(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_undef_type_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "typeattributeset", "attrs", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typeattributeset_not(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "type", "type_t", ")",
+ "(", "type", "t_t", ")",
+ "(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typeattributeset_undef_type_not_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "type", "type_t", ")",
+ "(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_typeattributeset(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typealias(CuTest *tc) {
+ char *line[] = {"(", "block", "foo",
+ "(", "typealias", ".foo.test", "type_t", ")",
+ "(", "type", "test", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typealias(test_db->ast->root->cl_head->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typealias_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "foo",
+ "(", "typealias", ".foo", "apache_alias", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typealias(test_db->ast->root->cl_head->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typebounds(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typebounds_repeatbind_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next, args);
+ int rc2 = cil_resolve_typebounds(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc2);
+}
+
+void test_cil_resolve_typebounds_type1_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typebounds_type2_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typebounds(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_typepermissive(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typepermissive(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_typepermissive_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "typepermissive", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_typepermissive(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nametypetransition_src_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "wrong", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_tgt_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "wrong", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_class_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "bar", "wrong", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nametypetransition_dest_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "bar", "file", "wrong", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nametypetransition(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_namedrange_anon(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "l", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "l", ")", ")",
+ "(", "call", "mm", "(", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_namedrange_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "l", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "l", ")", ")",
+ "(", "call", "mm", "(", "(", "DNE", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_namedrange(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "foo_range", "(", "low", "high", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "foo_range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_namedrange_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "levelrange", "foo_range", "(", "low", "high", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "DNE", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_type1_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_DNE", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_type2_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_DNE", "class_", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_class_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_DNE", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_call_level_l_anon(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "l", "high", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_l_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "l", "high", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c4", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_h_anon(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "h", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "h", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_call_level_h_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "h", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "h", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c4", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_rangetransition_level_l_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low_DNE", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_level_h_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high_DNE", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_l(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "(", "s0", "(", "c0", ")", ")", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_l_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "(", "s0", "(", "c_DNE", ")", ")", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_h(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_rangetransition_anon_level_h_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "(", "s_DNE", "(", "c0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_rangetransition(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classcommon(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+ "(", "common", "file", "(", "write", ")", ")",
+ "(", "classcommon", "file", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classcommon_no_class_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "classcommon", "foo", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classcommon_no_common_neg(CuTest *tc) {
+ char *line[] = {"(", "common", "foo", "(", "read", ")", ")",
+ "(", "classcommon", "foo", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_classcommon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classpermset_named(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+ "(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_named_namedpermlist(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "char", "baz", ")", ")",
+ "(", "permissionset", "baz", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_named_permlist_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "dne", "(", "read", ")", ")", ")",
+ "(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = test_db->ast->root->cl_head->next->next->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_classpermset_named_unnamedcps_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "char", "(", "read", ")", ")", ")",
+ "(", "classmapping", "files", "read", "char_w", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps;
+ cil_classpermset_init(&cps);
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next->next->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_classpermset_anon(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "(", "char", "(", "read", ")", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_anon_namedpermlist(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "(", "char", "baz", ")", ")",
+ "(", "permissionset", "baz", "(", "read", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_classpermset_anon_permlist_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "classmapping", "files", "read", "(", "char", "(", "dne", ")", ")", ")",
+ "(", "class", "char", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_classpermset *cps = ((struct cil_classmapping*)test_db->ast->root->cl_head->next->data)->classpermsets_str->head->data;
+
+ int rc = cil_resolve_classpermset(test_db->ast->root->cl_head->next, cps, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_avrule_permset(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "permissionset", "baz", "(", "open", "write", ")", ")",
+ "(", "allow", "test", "foo", "(", "bar", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_avrule_permset_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "permissionset", "baz", "(", "open", "close", ")", ")",
+ "(", "allow", "test", "foo", "(", "bar", "dne", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_permset_permdne_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "permissionset", "baz", "(", "open", "dne", ")", ")",
+ "(", "allow", "test", "foo", "(", "bar", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_firsttype_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "fail1", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_secondtype_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "fail2", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_class_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "fail3", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_avrule_perm_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(", "execute", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_avrule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_transition_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_objdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_transition_resultdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_change_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_objdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_change_resultdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_type_rule_member_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_objdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_type_rule_member_resultdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_type_rule(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_filecon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_filecon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "conn", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_filecon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_filecon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_filecon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_portcon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "portcon", "udp", "25", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_portcon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "portcon", "udp", "25", "conn", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_portcon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "portcon", "udp", "25", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_portcon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "portcon", "udp", "25", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_portcon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_genfscon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_genfscon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "genfscon", "type", "path", "conn", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_genfscon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "genfscon", "type", "path", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_genfscon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "genfscon", "type", "path", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_genfscon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_ipv4(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "netmask", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_ipv6(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+ "(", "ipaddr", "netmask", "2001:0DB8:AC10:FE01::", ")",
+ "(", "nodecon", "ip", "netmask", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonipaddr_ipv4(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "(", "192.168.1.1", ")", "netmask", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonnetmask_ipv4(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "(", "192.168.1.1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonipaddr_ipv6(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "netmask", "2001:0DB8:AC10:FE01::", ")",
+ "(", "nodecon", "(", "2001:0DB8:AC10:FE01::", ")", "netmask", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anonnetmask_ipv6(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+ "(", "nodecon", "ip", "(", "2001:0DB8:AC10:FE01::", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_diffipfam_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "2001:0DB8:AC10:FE01::", ")",
+ "(", "nodecon", "ip", "(", "192.168.1.1", ")", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_nodecon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "n", "netmask", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_ipaddr_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "n", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_netmask_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "ip", "conn", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_nodecon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "ip", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_nodecon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "ip", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_nodecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon(CuTest *tc) {
+ char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_netifcon_otf_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_interface_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed_packet_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_unnamed_otf_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")",
+ "(", "system_u", "foo_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_netifcon_sublist_secondlist_missing_neg(CuTest *tc) {
+ char *line[] = {"(", "netifcon", "eth1",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_netifcon(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pirqcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pirqcon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "etc_t", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "pirqcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pirqcon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "pirqcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pirqcon(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_iomemcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_iomemcon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "iomemcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_iomemcon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "etc_t", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "iomemcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_iomemcon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "iomemcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_iomemcon(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ioportcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ioportcon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "ioportcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ioportcon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "etc_t", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "ioportcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ioportcon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "ioportcon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_ioportcon(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pcidevicecon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pcidevicecon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pcidevicecon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_pcidevicecon_anon_context(CuTest *tc) {
+ char *line[] = {"(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "etc_t", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "pcidevicecon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_pcidevicecon_anon_context_neg(CuTest *tc) {
+ char *line[] = {"(", "pcidevicecon", "1", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_pcidevicecon(test_db->ast->root->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_fsuse(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+ "(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_fsuse_nocontext_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+ "(", "fsuse", "xattr", "ext3", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_fsuse_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+ "(", "fsuse", "xattr", "ext3", "conn", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_fsuse_anon(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "fsuse", "xattr", "ext3", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_fsuse_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "fsuse", "xattr", "ext3", "(", "system_uu", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_fsuse(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "sid", "test", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_levels(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "sid", "test", ")",
+ "(", "sidcontext", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *level = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+ cil_resolve_level(level, (struct cil_level*)level->data, args);
+ cil_resolve_level(level->next, (struct cil_level*)level->next->data, args);
+ int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")",
+ "(", "sid", "test", ")",
+ "(", "sidcontext", "test", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *context = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+ cil_resolve_context(context, (struct cil_context*)context->data, args);
+
+ int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context_wrongname_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "context", "con", "(", "blah_u", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")",
+ "(", "sid", "test", ")",
+ "(", "sidcontext", "test", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ struct cil_tree_node *context = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+ cil_resolve_context(context, (struct cil_context*)context->data, args);
+
+ int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_sidcontext_named_context_invaliduser_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "sid", "test", ")",
+ "(", "sidcontext", "test", "(", "", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ int rc = cil_resolve_sidcontext(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_blockinherit(CuTest *tc) {
+ char *line[] = {"(", "block", "baz", "(", "type", "b", ")", ")",
+ "(", "block", "foo", "(", "type", "a", ")",
+ "(", "blockinherit", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_blockinherit(test_db->ast->root->cl_head->next->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_blockinherit_blockstrdne_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "baz", "(", "type", "b", ")", ")",
+ "(", "block", "foo", "(", "type", "a", ")",
+ "(", "blockinherit", "dne", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_blockinherit(test_db->ast->root->cl_head->next->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_in_block(CuTest *tc) {
+ char *line[] = {"(", "class", "char", "(", "read", ")", ")",
+ "(", "block", "foo", "(", "type", "a", ")", ")",
+ "(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_in_blockstrdne_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "char", "(", "read", ")", ")",
+ "(", "in", "foo", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_in(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_in_macro(CuTest *tc) {
+ char *line[] = {"(", "class", "char", "(", "read", "write", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "allow", "foo", "bar", "(", "file", "(", "write", ")", ")", ")", ")",
+ "(", "in", "mm", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_in_optional(CuTest *tc) {
+ char *line[] = {"(", "class", "char", "(", "read", "write", ")", ")",
+ "(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")",
+ "(", "in", "opt", "(", "allow", "test", "baz", "(", "char", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_in(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_noparam(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "qaz", "b", "file", "(", "read", ")", ")", ")",
+ "(", "call", "mm", "(", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_type(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_role(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "role", "a", ")", ")",
+ "(", "role", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "role_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_user(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "user", "a", ")", ")",
+ "(", "user", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "user_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_sens(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "sens", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")",
+ "(", "sensitivity", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "sens", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_cat(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "category", "a", ")", ")",
+ "(", "category", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "c0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")",
+ "(", "macro", "mm", "(", "(", "categoryset", "foo", ")", ")",
+ "(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+ "(", "call", "mm", "(", "somecats", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "macro", "mm", "(", "(", "categoryset", "foo", ")", ")",
+ "(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "c0", "c1", "c2", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_catset_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "macro", "mm", "(", "(", "categoryset", "foo", ")", ")",
+ "(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "c5", "(", "c2", ")", "c4", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_level(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_level_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_level_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", "(", "c5", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.0.1", ")",
+ "(", "ipaddr", "ip", "192.168.0.1", ")",
+ "(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+ "(", "nodecon", "addr", "netmask", "con", ")", ")",
+ "(", "call", "mm", "(", "ip", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_ipaddr_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.0.1", ")",
+ "(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+ "(", "nodecon", "addr", "netmask", "con", ")", ")",
+ "(", "call", "mm", "(", "(", "192.168.1.1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_ipaddr_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.0.1", ")",
+ "(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+ "(", "nodecon", "addr", "netmask", "con", ")", ")",
+ "(", "call", "mm", "(", "(", "192.1.1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_class(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classmap(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classmap", "a", ")", ")",
+ "(", "classmapping", "a", "read", "(", "file", "(", "open", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "read", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_permset(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "open", ")", ")",
+ "(", "type", "dead", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "baz", "(", "close", "read", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")",
+ "(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_permset_anon(CuTest *tc) {
+ char *line[] = {"(", "type", "dead", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "baz", "(", "close", "read", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")",
+ "(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "read", "open", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_named(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "file", "(", "open", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "char_w", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_anon(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_classpermset_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "(", "file", "(", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknown_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *macro_node = NULL;
+ cil_resolve_name(test_db->ast->root->cl_head->next->next->next, ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str, CIL_SYM_BLOCKS, args, ¯o_node);
+ ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro = (struct cil_macro*)macro_node->data;
+ free(((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str);
+ ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro_str = NULL;
+
+ ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data)->macro->params->head->flavor = CIL_NETIFCON;
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknowncall_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "m", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_call1_extraargs_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", "bar", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_copy_dup(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "qaz", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call1_missing_arg_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "l", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_paramsflavor_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *macro_node = NULL;
+
+ struct cil_call *new_call = ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data);
+ cil_resolve_name(test_db->ast->root->cl_head->next->next->next, new_call->macro_str, CIL_SYM_BLOCKS, args, ¯o_node);
+ new_call->macro = (struct cil_macro*)macro_node->data;
+ struct cil_list_item *item = new_call->macro->params->head;
+ item->flavor = CIL_CONTEXT;
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call1_unknownflavor_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *macro_node = NULL;
+
+ struct cil_call *new_call = ((struct cil_call*)test_db->ast->root->cl_head->next->next->next->data);
+ cil_resolve_name(test_db->ast->root->cl_head->next->next->next, new_call->macro_str, CIL_SYM_BLOCKS, args, ¯o_node);
+ new_call->macro = (struct cil_macro*)macro_node->data;
+ struct cil_list_item *item = new_call->macro->params->head;
+ ((struct cil_param*)item->data)->flavor = CIL_CONTEXT;
+
+ int rc = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call2_type(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_role(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "role", "a", ")", ")",
+ "(", "role", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "role_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_user(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "user", "a", ")", ")",
+ "(", "user", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "user_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_sens(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "sens", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "sensitivity", "a", ")", ")",
+ "(", "sensitivity", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "sens", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_cat(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "category", "a", ")", ")",
+ "(", "category", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "c0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_catset(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")",
+ "(", "macro", "mm", "(", "(", "categoryset", "foo", ")", ")",
+ "(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+ "(", "call", "mm", "(", "somecats", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_catset_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "macro", "mm", "(", "(", "categoryset", "foo", ")", ")",
+ "(", "level", "bar", "(", "s0", "foo", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "c0", "c1", "c2", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_permset(CuTest *tc) {
+ char *line[] = {"(", "permissionset", "foo", "(", "read", "open", ")", ")",
+ "(", "class", "dead", "(", "close", ")", ")",
+ "(", "class", "bar", "(", "close", ")", ")",
+ "(", "class", "baz", "(", "close", ")", ")",
+ "(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")",
+ "(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_permset_anon(CuTest *tc) {
+ char *line[] = {"(", "class", "dead", "(", "close", ")", ")",
+ "(", "class", "bar", "(", "close", ")", ")",
+ "(", "class", "baz", "(", "close", ")", ")",
+ "(", "macro", "mm", "(", "(", "permissionset", "a", ")", ")",
+ "(", "allow", "dead", "bar", "(", "baz", "a", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "read", "open", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classpermset_named(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "classpermissionset", "char_w", "(", "file", "(", "open", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "char_w", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classpermset_anon(CuTest *tc) {
+ char *line[] = {"(", "classmap", "files", "(", "read", ")", ")",
+ "(", "class", "file", "(", "open", ")", ")",
+ "(", "macro", "mm", "(", "(", "classpermissionset", "a", ")", ")",
+ "(", "classmapping", "files", "read", "a", ")", ")",
+ "(", "call", "mm", "(", "(", "file", "(", "open", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_class(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_classmap(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "open", ")", ")",
+ "(", "classmap", "files", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "classmap", "a", ")", ")",
+ "(", "classmapping", "a", "read", "(", "file", "(", "open", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "files", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+}
+
+void test_cil_resolve_call2_level(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_level_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_ipaddr(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.0.1", ")",
+ "(", "ipaddr", "ip", "192.168.0.1", ")",
+ "(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+ "(", "nodecon", "addr", "netmask", "con", ")", ")",
+ "(", "call", "mm", "(", "ip", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_ipaddr_anon(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "lvl_l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "lvl_h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")",
+ "(", "ipaddr", "netmask", "192.168.0.1", ")",
+ "(", "macro", "mm", "(", "(", "ipaddr", "addr", ")", ")",
+ "(", "nodecon", "addr", "netmask", "con", ")", ")",
+ "(", "call", "mm", "(", "(", "192.168.1.1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_call2_unknown_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ ((struct cil_args*)((struct cil_list_item *)((struct cil_call *)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data)->args->head)->data)->flavor = CIL_SYM_UNKNOWN;
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_call2_name_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "class", "a", ")", ")",
+ "(", "class", "b", "(", "read", ")", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "a", CIL_SYM_TYPES, &test_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_call_args_multipleparams(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "level", "l", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "h", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "lvl_l", ")", "(", "level", "lvl_h", ")", ")",
+ "(", "context", "foo", "(", "system_u", "role_r", "type_t", "(", "lvl_l", "lvl_h", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "l", "h", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->data, "lvl_h", CIL_SYM_LEVELS, &test_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_name_call_args_diffflavor(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qaz", CIL_LEVEL, &test_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_callnull_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args(NULL, "qaz", CIL_LEVEL, &test_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_namenull_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, NULL, CIL_LEVEL, &test_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_callargsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qas", CIL_LEVEL, &test_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_name_call_args_name_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node = NULL;
+ //cil_tree_node_init(&test_node);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ cil_resolve_call2(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_name_call_args((struct cil_call *)test_db->ast->root->cl_head->next->next->next->data, "qas", CIL_TYPE, &test_node);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_expr_stack_bools(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(bif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_tunables(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_type(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "type", "t1", ")",
+ "(", "type", "type_t", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "t1", "type_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_role(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "role", "r1", ")",
+ "(", "role", "role_r", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "role_r", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_user(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "user", "u1", ")",
+ "(", "user", "user_u", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "u1", "user_u", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_constrain *cons = (struct cil_constrain*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(cons->expr, test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_expr_stack_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "beef", "baf", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ int rc = cil_resolve_expr_stack(bif->expr_stack,test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_expr_stack_emptystr_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_booleanif *bif = (struct cil_booleanif*)test_db->ast->root->cl_head->next->next->next->data;
+ ((struct cil_conditional*)bif->expr_stack->head->data)->str = NULL;
+
+ int rc = cil_resolve_expr_stack(bif->expr_stack,test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_boolif(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_boolif(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_boolif_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "dne", "N/A", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_boolif(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_evaluate_expr_stack_and(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_not(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "not", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_or(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "or", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_xor(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "xor", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_eq(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "eq", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_neq(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "neq", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_oper1(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "tunable", "baz", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "(", "or", "foo", "bar", ")", "baz", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "jaz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_evaluate_expr_stack_oper2(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "tunable", "baz", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "baz", "(", "or", "foo", "bar", ")", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "jaz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tunableif *tif = (struct cil_tunableif*)test_db->ast->root->cl_head->next->next->next->next->data;
+
+ cil_resolve_expr_stack(tif->expr_stack, test_db->ast->root->cl_head->next->next->next->next, args);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+/*
+void test_cil_evaluate_expr_stack_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "neq", "foo", "bar", ")",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint16_t result = CIL_FALSE;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ struct cil_conditional *new_cond;
+ cil_conditional_init(&new_cond);
+ new_cond->flavor = CIL_COND;
+ char *baz = "baz";
+ new_cond->str = baz;
+ new_cond->flavor = CIL_TUNABLE;
+
+ struct cil_tunableif *tif = test_db->ast->root->cl_head->next->next->next->next->data;
+
+ test_node->data = new_cond;
+ test_node->cl_head = tif->expr_stack;
+ tif->expr_stack->parent = test_node;
+
+ cil_resolve_expr_stack(test_db, tif->expr_stack, test_db->ast->root->cl_head->next->next->next, NULL);
+ int rc = cil_evaluate_expr_stack(tif->expr_stack, &result);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+*/
+void test_cil_resolve_tunif_false(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "false",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_tunif_true(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "true", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_tunif_resolveexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "dne", "N/A", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_tunif(test_db->ast->root->cl_head->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+/*
+void test_cil_resolve_tunif_evaluateexpr_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ struct cil_tree_node *test_node;
+ cil_tree_node_init(&test_node);
+
+ struct cil_conditional *new_cond;
+ cil_conditional_init(&new_cond);
+ new_cond->flavor = CIL_COND;
+ char *baz = "baz";
+ new_cond->str = baz;
+ new_cond->flavor = CIL_TUNABLE;
+
+ struct tunableif *tif = test_db->ast->root->cl_head->next->next->next->data;
+
+ test_node->data = new_cond;
+ test_node->cl_head = tif->expr_stack;
+ tif->expr_stack->parent = test_node;
+
+ int rc = cil_resolve_tunif(test_db, test_db->ast->root->cl_head->next->next->next, NULL);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+*/
+void test_cil_resolve_userbounds(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "user", "user2", ")",
+ "(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userbounds_exists_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "user", "user2", ")",
+ "(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+ int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_userbounds_user1_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "user", "user2", ")",
+ "(", "userbounds", "user_DNE", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userbounds_user2_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "user", "user2", ")",
+ "(", "userbounds", "user1", "user_DNE", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_userbounds(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletype(CuTest *tc) {
+ char *line[] = {"(", "role", "admin_r", ")",
+ "(", "type", "admin_t", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_roletype_type_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "admin_r", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_roletype_role_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "admin_t", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_roletype(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrole(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrole_user_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrole_role_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = cil_resolve_userrole(test_db->ast->root->cl_head->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userlevel", "foo_u", "low", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userlevel_macro(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+ "(", "userlevel", "foo_u", "l", ")", ")",
+ "(", "call", "mm", "(", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+
+ args->pass = CIL_PASS_CALL1;
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userlevel_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "macro", "mm", "(", "(", "level", "l", ")", ")",
+ "(", "userlevel", "foo_u", "l", ")", ")",
+ "(", "call", "mm", "(", "(", "DNE", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userlevel_level_anon(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "userlevel", "foo_u", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userlevel_level_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "userlevel", "foo_u", "(", "s0", "(", "DNE", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel_user_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userlevel", "DNE", "low", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userlevel_level_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userlevel", "foo_u", "DNE", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userlevel(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "userrange", "foo_u", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrange_macro(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+ "(", "userrange", "foo_u", "range", ")", ")",
+ "(", "call", "mm", "(", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userrange_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "macro", "mm", "(", "(", "levelrange", "range", ")", ")",
+ "(", "userrange", "foo_u", "range", ")", ")",
+ "(", "call", "mm", "(", "(", "DNE", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc2 = cil_resolve_call1(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc3 = cil_resolve_call2(test_db->ast->root->cl_head->next->next->next->next->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC2;
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+ args->callstack = test_db->ast->root->cl_head->next->next->next->next->next->next->next;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next->next->cl_head, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, SEPOL_OK, rc2);
+ CuAssertIntEquals(tc, SEPOL_OK, rc3);
+}
+
+void test_cil_resolve_userrange_range_anon(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userrange", "foo_u", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_userrange_range_anon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userrange", "foo_u", "(", "DNE", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange_user_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "userrange", "DNE", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_userrange_range_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "userrange", "foo_u", "DNE", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_senscat(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = cil_resolve_userrange(test_db->ast->root->cl_head->next->next->next->next->next, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_disable_children_helper_optional_enabled(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_optional_disabled(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ ((struct cil_optional *)test_db->ast->root->cl_head->data)->datum.state = CIL_STATE_DISABLED;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_block(CuTest *tc) {
+ char *line[] = {"(", "block", "a", "(", "type", "log", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_user(CuTest *tc) {
+ char *line[] = {"(", "user", "staff_u", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_role(CuTest *tc) {
+ char *line[] = {"(", "role", "role_r", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_type(CuTest *tc) {
+ char *line[] = {"(", "type", "type_t", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_typealias(CuTest *tc) {
+ char *line[] = {"(", "typealias", ".test.type", "type_t", ")", "(", "type", "test", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_common(CuTest *tc) {
+ char *line[] = {"(", "common", "foo", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_class(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_bool(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sens(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_cat(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_catset(CuTest *tc) {
+ char *line[] = {"(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sid(CuTest *tc) {
+ char *line[] = {"(", "sid", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_macro(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_context(CuTest *tc) {
+ char *line[] = {"(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_level(CuTest *tc) {
+ char *line[] = {"(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_policycap(CuTest *tc) {
+ char *line[] = {"(", "policycap", "foo", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_perm(CuTest *tc) {
+ char *line[] = {"(", "class", "foo", "(", "read", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_catalias(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_tunable(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "false", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_disable_children_helper_unknown(CuTest *tc) {
+ char *line[] = {"(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ uint32_t finished = 0;
+
+ int rc = __cil_disable_children_helper(test_db->ast->root->cl_head, &finished, NULL);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+
+/*
+ __cil_resolve_ast_node_helper test cases
+*/
+
+void test_cil_resolve_ast_node_helper_call1(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call1_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "m", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call2(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_call2_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "foo", "extra", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_boolif(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "foo", "bar", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_boolif_neg(CuTest *tc) {
+ char *line[] = {"(", "boolean", "foo", "true", ")",
+ "(", "boolean", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "booleanif", "(", "and", "dne", "N/A", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_tunif(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "foo", "bar", ")",
+ "(", "false",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_tunif_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")",
+ "(", "tunable", "bar", "false", ")",
+ "(", "class", "baz", "(", "read", ")", ")",
+ "(", "tunableif", "(", "and", "dne", "N/A", ")",
+ "(", "true",
+ "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catorder(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryorder", "(", "c0", "c1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catorder_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryorder", "(", "c8", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_dominance(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_dominance_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "sensitivity", "s2", ")",
+ "(", "dominance", "(", "s0", "s6", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roleallow(CuTest *tc) {
+ char *line[] = {"(", "role", "foo", ")", \
+ "(", "role", "bar", ")", \
+ "(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roleallow_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo", ")", \
+ "(", "roleallow", "foo", "bar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sensalias(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sensalias_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivityalias", "s0", "alias", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catalias(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catalias_neg(CuTest *tc) {
+ char *line[] = {"(", "categoryalias", "c0", "red", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catset(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "category", "c2", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catset_catlist_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c1", ")",
+ "(", "categoryset", "somecats", "(", "c0", "c1", "c2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catrange(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c0", "c255", ")", ")", NULL};
+
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+ cil_resolve_catorder(test_db->ast->root->cl_head->next->next, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ args->pass = CIL_PASS_MLS;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_catrange_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "categoryrange", "range", "(", "c255", "c0", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MLS, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_level(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "sensitivitycategory", "s0", "(", "c1", ")", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC2;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_level_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "sensitivitycategory", "s0", "(", "c1", ")", ")",
+ "(", "level", "l2", "(", "s8", "(", "c1", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_levelrange(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "dominance", "(", "s0", ")", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC2;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_levelrange_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "dominance", "(", "s0", ")", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "DNE", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_constrain(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "role", "r1", ")",
+ "(", "role", "r2", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_constrain_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", ")", ")",
+ "(", "class", "dir", "(", "create", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "role", "r1", ")",
+ "(", "role", "r2", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "r1", "r2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_mlsconstrain(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "create", "relabelto", ")", ")",
+ "(", "class", "dir", "(", "create", "relabelto", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_mlsconstrain_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+ "(", "class", "dir", "(", "read", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c1", ")",
+ "(", "level", "l2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "level", "h2", "(", "s0", "(", "c1", ")", ")", ")",
+ "(", "mlsconstrain", "(", "file", "(", "create", "relabelto", ")", ")", "(", "eq", "l2", "h2", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_context(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_context_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con",
+ "(", "system_u", "object_r", "netif_t", "DNE", "high", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC1, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+ __cil_verify_order(test_db->catorder, test_db->ast->root, CIL_CAT);
+
+ __cil_verify_order(test_db->dominance, test_db->ast->root, CIL_SENS);
+
+ args->pass = CIL_PASS_MLS;
+ cil_tree_walk(test_db->ast->root, __cil_resolve_ast_node_helper, NULL, NULL, args);
+
+ args->pass = CIL_PASS_MISC3;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, finished, 0);
+}
+
+void test_cil_resolve_ast_node_helper_senscat(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s1", "(", "c0", "c255", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_senscat_neg(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "sensitivity", "s1", ")",
+ "(", "dominance", "(", "s0", "s1", ")", ")",
+ "(", "category", "c0", ")",
+ "(", "category", "c255", ")",
+ "(", "categoryorder", "(", "c0", "c255", ")", ")",
+ "(", "sensitivitycategory", "s5", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "type", "bar_t", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "bar_t", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "role", "foobar_r", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "foo_r", ")",
+ "(", "type", "bar_t", ")",
+ "(", "class", "process", "(", "transition", ")", ")",
+ "(", "roletransition", "foo_r", "bar_t", "process", "foobar_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typeattributeset(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "type", "type_t", ")",
+ "(", "type", "type_tt", ")",
+ "(", "typeattributeset", "attrs", "(", "type_t", "type_tt", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg(CuTest *tc) {
+ char *line[] = {"(", "typeattribute", "attrs", ")",
+ "(", "type", "type_t", ")",
+ "(", "typeattributeset", "attrs", "(", "not", "t_t", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typealias(CuTest *tc) {
+ char *line[] = {"(", "block", "foo",
+ "(", "typealias", ".foo.test", "type_t", ")",
+ "(", "type", "test", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typealias_notype_neg(CuTest *tc) {
+ char *line[] = {"(", "block", "bar",
+ "(", "typealias", ".bar.test", "type_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typebounds(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typebounds_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_b", ")",
+ "(", "typebounds", "type_a", "type_b", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typepermissive(CuTest *tc) {
+ char *line[] = {"(", "type", "type_a", ")",
+ "(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_typepermissive_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "type_b", ")",
+ "(", "typepermissive", "type_a", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rangetransition(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_a", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rangetransition_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "class_", "(", "read", ")", ")",
+ "(", "type", "type_a", ")",
+ "(", "type", "type_b", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "rangetransition", "type_DNE", "type_b", "class_", "(", "low", "high", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nametypetransition(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nametypetransition_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "nametypetransition", "str", "foo", "bar", "file", "foobarrr", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_src_nores_neg(CuTest *tc) {
+ char *line[] = {"(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_class_nores_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "test", ")",
+ "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(", "read", "write", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_avrule_datum_null_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "bar", "(", "read", "write", "open", ")", ")",
+ "(", "type", "test", ")", "(", "type", "foo", ")",
+ "(", "allow", "test", "foo", "(", "bar", "(","fake", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_transition(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_transition_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typetransition", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_change(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_change_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typechange", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_member(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_type_rule_member_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "foo", ")",
+ "(", "class", "file", "(", "write", ")", ")",
+ "(", "type", "foobar", ")",
+ "(", "typemember", "foo", "bar", "file", "foobar", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_userbounds(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "user", "user2", ")",
+ "(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userbounds_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user1", ")",
+ "(", "userbounds", "user1", "user2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype(CuTest *tc) {
+ char *line[] = {"(", "role", "admin_r", ")",
+ "(", "type", "admin_t", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype_role_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "admin_t", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_roletype_type_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "admin_r", ")",
+ "(", "roletype", "admin_r", "admin_t", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole_user_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrole_role_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userlevel", "foo_u", "low", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "userlevel", "DNE", "low", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrange(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "userrange", "foo_u", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_userrange_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "foo_u", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "levelrange", "range", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")",
+ "(", "userrange", "DNE", "range", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+void test_cil_resolve_ast_node_helper_filecon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_filecon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "filecon", "root", "path", "file", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_portcon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "portcon", "udp", "25", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_portcon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "portcon", "udp", "25", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_genfscon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "genfscon", "type", "path", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_genfscon_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "genfscon", "type", "path", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "ip", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "ipp", "netmask", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodecon_netmask_neg(CuTest *tc) {
+ char *line[] = {"(", "user", "user_u", ")",
+ "(", "role", "role_r", ")",
+ "(", "type", "type_t", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "context", "con", "(", "user_u", "role_r", "type_t", "(", "low", "high", ")", ")", ")",
+ "(", "ipaddr", "ip", "192.168.1.1", ")",
+ "(", "ipaddr", "netmask", "192.168.1.1", ")",
+ "(", "nodecon", "ip", "nnetmask", "foo", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_netifcon(CuTest *tc) {
+ char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "context", "packet_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_netifcon_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pirqcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pirqcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pirqcon_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pirqcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_iomemcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "iomemcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_iomemcon_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "iomemcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_ioportcon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "ioportcon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_ioportcon_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "ioportcon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pcidevicecon(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pcidevicecon", "1", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_pcidevicecon_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "con", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "pcidevicecon", "1", "dne", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_fsuse(CuTest *tc) {
+ char *line[] = {"(", "sensitivity", "s0", ")",
+ "(", "category", "c0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "user", "system_u", ")",
+ "(", "role", "object_r", ")",
+ "(", "type", "netif_t", ")",
+ "(", "context", "con", "(", "system_u", "object_r", "netif_t", "(", "low", "high", ")", ")", ")",
+ "(", "fsuse", "xattr", "ext3", "con", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_fsuse_neg(CuTest *tc) {
+ char *line[] = {"(", "context", "if_default", "(", "system_u", "object_r", "etc_t", "(", "low", "high", ")", ")", ")",
+ "(", "netifcon", "eth0", "if_default", "packet_default", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sidcontext(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "level", "low", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "level", "high", "(", "s0", "(", "c0", ")", ")", ")",
+ "(", "sid", "test", "(", "blah_u", "blah_r", "blah_t", "(", "low", "high", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_sidcontext_neg(CuTest *tc) {
+ char *line[] = {"(", "category", "c0", ")",
+ "(", "categoryorder", "(", "c0", ")", ")",
+ "(", "sensitivity", "s0", ")",
+ "(", "sensitivitycategory", "s0", "(", "c0", ")", ")",
+ "(", "type", "blah_t", ")",
+ "(", "role", "blah_r", ")",
+ "(", "user", "blah_u", ")",
+ "(", "sidcontext", "test", "(", "", "blah_r", "blah_t", "(", "(", "s0", "(", "c0", ")", ")", "(", "s0", "(", "c0", ")", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next->next->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_blockinherit(CuTest *tc) {
+ char *line[] = {"(", "block", "baz", "(", "type", "foo", ")", ")",
+ "(", "block", "bar", "(", "type", "a", ")",
+ "(", "blockinherit", "baz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_BLKIN, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_classcommon(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+ "(", "common", "file", "(", "write", ")", ")",
+ "(", "classcommon", "file", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_classcommon_neg(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+ "(", "classcommon", "file", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_rolebounds(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "role", "role2", ")",
+ "(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_rolebounds_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "role1", ")",
+ "(", "rolebounds", "role1", "role2", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ENOENT, rc);
+}
+
+
+void test_cil_resolve_ast_node_helper_callstack(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_tree_node *test_ast_node_call;
+ cil_tree_node_init(&test_ast_node_call);
+ test_ast_node_call->flavor = CIL_CALL;
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_call(CuTest *tc) {
+ char *line[] = {"(", "call", "mm", "(", "foo", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_tree_node *test_ast_node_call;
+ cil_tree_node_init(&test_ast_node_call);
+ test_ast_node_call->flavor = CIL_CALL;
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optional(CuTest *tc) {
+ char *line[] = {"(", "optional", "opt", "(", "allow", "foo", "bar", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_tree_node *test_ast_node_opt;
+ cil_tree_node_init(&test_ast_node_opt);
+ test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ // set optional to disabled
+ ((struct cil_symtab_datum *)test_db->ast->root->cl_head->data)->state = CIL_STATE_DISABLED;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_macro(CuTest *tc) {
+ char *line[] = {"(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack(CuTest *tc) {
+ char *line[] = {"(", "class", "baz", "(", "read", ")", ")",
+ "(", "type", "foo", ")",
+ "(", "type", "bar", ")",
+ "(", "optional", "opt", "(", "allow", "foo", "bar", "(", "baz", "(", "read", ")", ")", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_tree_node *test_ast_node_opt;
+ cil_tree_node_init(&test_ast_node_opt);
+ test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack_tunable_neg(CuTest *tc) {
+ char *line[] = {"(", "tunable", "foo", "true", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node_opt;
+ cil_tree_node_init(&test_ast_node_opt);
+ test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, test_ast_node_opt, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optstack_macro_neg(CuTest *tc) {
+ char *line[] = {"(", "type", "qaz", ")",
+ "(", "class", "file", "(", "read", ")", ")",
+ "(", "macro", "mm", "(", "(", "type", "a", ")", ")",
+ "(", "type", "b", ")",
+ "(", "allow", "a", "b", "(", "file", "(", "read", ")", ")", ")", ")",
+ "(", "call", "mm", "(", "qaz", ")", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node_opt;
+ cil_tree_node_init(&test_ast_node_opt);
+ test_ast_node_opt->flavor = CIL_OPTIONAL;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_CALL1, &changed, NULL, test_ast_node_opt, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ cil_resolve_call1(test_db->ast->root->cl_head->next->next, args);
+
+ args->pass = CIL_PASS_CALL2;
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
+void test_cil_resolve_ast_node_helper_nodenull_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_TIF, &changed, NULL, NULL, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(NULL, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_extraargsnull_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, NULL);
+ CuAssertIntEquals(tc, 0, finished);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_dbflavor_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_pass_neg(CuTest *tc) {
+ char *line[] = {"(", "role", "staff_r", ")",
+ "(", "user", "staff_u", ")",
+ "(", "userrole", "staff_u", "staff_r", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ uint32_t finished = 0;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC3, &changed, NULL, NULL, NULL);
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_ERR, rc);
+}
+
+void test_cil_resolve_ast_node_helper_optfailedtoresolve(CuTest *tc) {
+ char *line[] = {"(", "class", "file", "(", "read", ")", ")",
+ "(", "classcommon", "file", "file", ")", NULL};
+
+ struct cil_tree *test_tree;
+ gen_test_tree(&test_tree, line);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ struct cil_optional *opt;
+ cil_optional_init(&opt);
+
+ struct cil_tree_node *test_ast_node_opt;
+ cil_tree_node_init(&test_ast_node_opt);
+ test_ast_node_opt->flavor = CIL_OPTIONAL;
+ test_ast_node_opt->data = opt;
+
+ uint32_t changed = CIL_FALSE;
+ struct cil_args_resolve *args = gen_resolve_args(test_db, CIL_PASS_MISC2, &changed, NULL, test_ast_node_opt, NULL);
+
+ uint32_t finished = 0;
+
+ cil_build_ast(test_db, test_tree->root, test_db->ast->root);
+
+ int rc = __cil_resolve_ast_node_helper(test_db->ast->root->cl_head->next, &finished, args);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertIntEquals(tc, 0, finished);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_resolve_ast.h b/libsepol/cil/test/unit/test_cil_resolve_ast.h
new file mode 100644
index 0000000..394efde
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_resolve_ast.h
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_RESOLVE_AST_H_
+#define TEST_CIL_RESOLVE_AST_H_
+
+#include "CuTest.h"
+
+void test_cil_resolve_name(CuTest *);
+void test_cil_resolve_name_invalid_type_neg(CuTest *);
+
+void test_cil_resolve_ast_curr_null_neg(CuTest *);
+
+
+/*
+ cil_resolve test cases
+*/
+
+void test_cil_resolve_roleallow(CuTest *);
+void test_cil_resolve_roleallow_srcdecl_neg(CuTest *);
+void test_cil_resolve_roleallow_tgtdecl_neg(CuTest *);
+
+void test_cil_resolve_rolebounds(CuTest *tc);
+void test_cil_resolve_rolebounds_exists_neg(CuTest *tc);
+void test_cil_resolve_rolebounds_role1_neg(CuTest *tc);
+void test_cil_resolve_rolebounds_role2_neg(CuTest *tc);
+
+void test_cil_resolve_sensalias(CuTest *);
+void test_cil_resolve_sensalias_sensdecl_neg(CuTest *);
+
+void test_cil_resolve_catalias(CuTest *);
+void test_cil_resolve_catalias_catdecl_neg(CuTest *);
+
+void test_cil_resolve_catorder(CuTest *);
+void test_cil_resolve_catorder_neg(CuTest *);
+
+void test_cil_resolve_dominance(CuTest *);
+void test_cil_resolve_dominance_neg(CuTest *);
+
+void test_cil_resolve_cat_list(CuTest *);
+void test_cil_resolve_cat_list_catlistnull_neg(CuTest *);
+void test_cil_resolve_cat_list_rescatlistnull_neg(CuTest *);
+void test_cil_resolve_cat_list_catrange(CuTest *);
+void test_cil_resolve_cat_list_catrange_neg(CuTest *);
+void test_cil_resolve_cat_list_catname_neg(CuTest *);
+
+void test_cil_resolve_catset(CuTest *);
+void test_cil_resolve_catset_catlist_neg(CuTest *);
+
+void test_cil_resolve_catrange(CuTest *);
+void test_cil_resolve_catrange_catloworder_neg(CuTest *);
+void test_cil_resolve_catrange_cathighorder_neg(CuTest *);
+void test_cil_resolve_catrange_cat1_neg(CuTest *);
+void test_cil_resolve_catrange_cat2_neg(CuTest *);
+
+void test_cil_resolve_senscat(CuTest *);
+void test_cil_resolve_senscat_catrange_neg(CuTest *);
+void test_cil_resolve_senscat_catsetname(CuTest *);
+void test_cil_resolve_senscat_catsetname_neg(CuTest *);
+void test_cil_resolve_senscat_sublist(CuTest *);
+void test_cil_resolve_senscat_missingsens_neg(CuTest *);
+void test_cil_resolve_senscat_sublist_neg(CuTest *);
+void test_cil_resolve_senscat_category_neg(CuTest *);
+void test_cil_resolve_senscat_currrangecat(CuTest *);
+void test_cil_resolve_senscat_currrangecat_neg(CuTest *);
+
+void test_cil_resolve_level(CuTest *);
+void test_cil_resolve_level_catlist(CuTest *);
+void test_cil_resolve_level_catset(CuTest *);
+void test_cil_resolve_level_catset_name_neg(CuTest *);
+void test_cil_resolve_level_sens_neg(CuTest *);
+void test_cil_resolve_level_cat_neg(CuTest *);
+void test_cil_resolve_level_senscat_neg(CuTest *);
+
+void test_cil_resolve_levelrange_namedlvl(CuTest *);
+void test_cil_resolve_levelrange_namedlvl_low_neg(CuTest *);
+void test_cil_resolve_levelrange_namedlvl_high_neg(CuTest *);
+void test_cil_resolve_levelrange_anonlvl(CuTest *);
+void test_cil_resolve_levelrange_anonlvl_low_neg(CuTest *);
+void test_cil_resolve_levelrange_anonlvl_high_neg(CuTest *);
+
+void test_cil_resolve_constrain(CuTest *);
+void test_cil_resolve_constrain_class_neg(CuTest *);
+void test_cil_resolve_constrain_perm_neg(CuTest *);
+void test_cil_resolve_constrain_perm_resolve_neg(CuTest *);
+
+void test_cil_resolve_context(CuTest *);
+void test_cil_resolve_context_macro(CuTest *);
+void test_cil_resolve_context_macro_neg(CuTest *);
+void test_cil_resolve_context_namedrange(CuTest *);
+void test_cil_resolve_context_namedrange_neg(CuTest *);
+void test_cil_resolve_context_macro_namedrange_anon(CuTest *);
+void test_cil_resolve_context_user_neg(CuTest *);
+void test_cil_resolve_context_role_neg(CuTest *);
+void test_cil_resolve_context_type_neg(CuTest *);
+void test_cil_resolve_context_anon_level_neg(CuTest *);
+
+void test_cil_resolve_roletransition(CuTest *);
+void test_cil_resolve_roletransition_srcdecl_neg(CuTest *);
+void test_cil_resolve_roletransition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_roletransition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_typeattributeset_type_in_multiple_attrs(CuTest *);
+void test_cil_resolve_typeattributeset_multiple_excludes_with_not(CuTest *);
+void test_cil_resolve_typeattributeset_multiple_types_with_and(CuTest *);
+void test_cil_resolve_typeattributeset_using_attr(CuTest *);
+void test_cil_resolve_typeattributeset_name_neg(CuTest *);
+void test_cil_resolve_typeattributeset_undef_type_neg(CuTest *);
+void test_cil_resolve_typeattributeset_not(CuTest *);
+void test_cil_resolve_typeattributeset_undef_type_not_neg(CuTest *);
+
+void test_cil_resolve_typealias(CuTest *);
+void test_cil_resolve_typealias_neg(CuTest *);
+
+void test_cil_resolve_typebounds(CuTest *);
+void test_cil_resolve_typebounds_repeatbind_neg(CuTest *);
+void test_cil_resolve_typebounds_type1_neg(CuTest *);
+void test_cil_resolve_typebounds_type2_neg(CuTest *);
+
+void test_cil_resolve_typepermissive(CuTest *);
+void test_cil_resolve_typepermissive_neg(CuTest *);
+
+void test_cil_resolve_nametypetransition(CuTest *);
+void test_cil_resolve_nametypetransition_src_neg(CuTest *);
+void test_cil_resolve_nametypetransition_tgt_neg(CuTest *);
+void test_cil_resolve_nametypetransition_class_neg(CuTest *);
+void test_cil_resolve_nametypetransition_dest_neg(CuTest *);
+
+void test_cil_resolve_rangetransition(CuTest *);
+void test_cil_resolve_rangetransition_namedrange(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_anon(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_namedrange_neg(CuTest *);
+void test_cil_resolve_rangetransition_type1_neg(CuTest *);
+void test_cil_resolve_rangetransition_type2_neg(CuTest *);
+void test_cil_resolve_rangetransition_class_neg(CuTest *);
+void test_cil_resolve_rangetransition_call_level_l_anon(CuTest *);
+void test_cil_resolve_rangetransition_call_level_l_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_call_level_h_anon(CuTest *);
+void test_cil_resolve_rangetransition_call_level_h_anon_neg(CuTest *);
+void test_cil_resolve_rangetransition_level_l_neg(CuTest *);
+void test_cil_resolve_rangetransition_level_h_neg(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_l(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_l_neg(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_h(CuTest *);
+void test_cil_resolve_rangetransition_anon_level_h_neg(CuTest *);
+
+void test_cil_resolve_classcommon(CuTest *);
+void test_cil_resolve_classcommon_no_class_neg(CuTest *);
+void test_cil_resolve_classcommon_neg(CuTest *);
+void test_cil_resolve_classcommon_no_common_neg(CuTest *);
+
+void test_cil_resolve_classmapping_named(CuTest *);
+void test_cil_resolve_classmapping_anon(CuTest *);
+void test_cil_resolve_classmapping_anon_inmacro(CuTest *);
+void test_cil_resolve_classmapping_anon_inmacro_neg(CuTest *);
+void test_cil_resolve_classmapping_named_classmapname_neg(CuTest *);
+void test_cil_resolve_classmapping_anon_classmapname_neg(CuTest *);
+void test_cil_resolve_classmapping_anon_permset_neg(CuTest *);
+
+void test_cil_resolve_classpermset_named(CuTest *);
+void test_cil_resolve_classpermset_named_namedpermlist(CuTest *);
+void test_cil_resolve_classpermset_named_permlist_neg(CuTest *);
+void test_cil_resolve_classpermset_named_unnamedcps_neg(CuTest *);
+void test_cil_resolve_classpermset_anon(CuTest *);
+void test_cil_resolve_classpermset_anon_namedpermlist(CuTest *);
+void test_cil_resolve_classpermset_anon_permlist_neg(CuTest *);
+
+void test_cil_resolve_avrule(CuTest *);
+void test_cil_resolve_avrule_permset(CuTest *);
+void test_cil_resolve_avrule_permset_neg(CuTest *);
+void test_cil_resolve_avrule_permset_permdne_neg(CuTest *);
+void test_cil_resolve_avrule_firsttype_neg(CuTest *);
+void test_cil_resolve_avrule_secondtype_neg(CuTest *);
+void test_cil_resolve_avrule_class_neg(CuTest *);
+void test_cil_resolve_avrule_perm_neg(CuTest *);
+
+void test_cil_resolve_type_rule_transition(CuTest *);
+void test_cil_resolve_type_rule_transition_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_transition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_type_rule_change(CuTest *);
+void test_cil_resolve_type_rule_change_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_change_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_type_rule_member(CuTest *);
+void test_cil_resolve_type_rule_member_srcdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_tgtdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_objdecl_neg(CuTest *);
+void test_cil_resolve_type_rule_member_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_filecon(CuTest *);
+void test_cil_resolve_filecon_neg(CuTest *);
+void test_cil_resolve_filecon_anon_context(CuTest *);
+void test_cil_resolve_filecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_filecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_filecon_neg(CuTest *tc);
+
+void test_cil_resolve_portcon(CuTest *);
+void test_cil_resolve_portcon_neg(CuTest *);
+void test_cil_resolve_portcon_anon_context(CuTest *);
+void test_cil_resolve_portcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_portcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_portcon_neg(CuTest *tc);
+
+void test_cil_resolve_genfscon(CuTest *);
+void test_cil_resolve_genfscon_neg(CuTest *);
+void test_cil_resolve_genfscon_anon_context(CuTest *);
+void test_cil_resolve_genfscon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_genfscon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_genfscon_neg(CuTest *tc);
+
+void test_cil_resolve_nodecon_ipv4(CuTest *);
+void test_cil_resolve_nodecon_ipv6(CuTest *);
+void test_cil_resolve_nodecon_anonipaddr_ipv4(CuTest *);
+void test_cil_resolve_nodecon_anonnetmask_ipv4(CuTest *);
+void test_cil_resolve_nodecon_anonipaddr_ipv6(CuTest *);
+void test_cil_resolve_nodecon_anonnetmask_ipv6(CuTest *);
+void test_cil_resolve_nodecon_diffipfam_neg(CuTest *);
+void test_cil_resolve_nodecon_context_neg(CuTest *);
+void test_cil_resolve_nodecon_ipaddr_neg(CuTest *);
+void test_cil_resolve_nodecon_netmask_neg(CuTest *);
+void test_cil_resolve_nodecon_anon_context(CuTest *);
+void test_cil_resolve_nodecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_nodecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodecon_ipaddr_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodecon_netmask_neg(CuTest *tc);
+
+void test_cil_resolve_netifcon(CuTest *);
+void test_cil_resolve_netifcon_otf_neg(CuTest *);
+void test_cil_resolve_netifcon_interface_neg(CuTest *);
+void test_cil_resolve_netifcon_unnamed(CuTest *);
+void test_cil_resolve_netifcon_unnamed_packet_neg(CuTest *);
+void test_cil_resolve_netifcon_unnamed_otf_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_netifcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_netifcon_neg(CuTest *tc);
+
+void test_cil_resolve_pirqcon(CuTest *);
+void test_cil_resolve_pirqcon_context_neg(CuTest *);
+void test_cil_resolve_pirqcon_anon_context(CuTest *);
+void test_cil_resolve_pirqcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_pirqcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_pirqcon_neg(CuTest *tc);
+
+void test_cil_resolve_iomemcon(CuTest *);
+void test_cil_resolve_iomemcon_context_neg(CuTest *);
+void test_cil_resolve_iomemcon_anon_context(CuTest *);
+void test_cil_resolve_iomemcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_iomemcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_iomemcon_neg(CuTest *tc);
+
+void test_cil_resolve_ioportcon(CuTest *);
+void test_cil_resolve_ioportcon_context_neg(CuTest *);
+void test_cil_resolve_ioportcon_anon_context(CuTest *);
+void test_cil_resolve_ioportcon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_ioportcon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_ioportcon_neg(CuTest *tc);
+
+void test_cil_resolve_pcidevicecon(CuTest *);
+void test_cil_resolve_pcidevicecon_context_neg(CuTest *);
+void test_cil_resolve_pcidevicecon_anon_context(CuTest *);
+void test_cil_resolve_pcidevicecon_anon_context_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_pcidevicecon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_pcidevicecon_neg(CuTest *tc);
+
+void test_cil_resolve_fsuse(CuTest *);
+void test_cil_resolve_fsuse_neg(CuTest *);
+void test_cil_resolve_fsuse_anon(CuTest *);
+void test_cil_resolve_fsuse_anon_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_fsuse(CuTest *tc);
+void test_cil_resolve_ast_node_helper_fsuse_neg(CuTest *tc);
+
+void test_cil_resolve_sidcontext(CuTest *);
+void test_cil_resolve_sidcontext_named_levels(CuTest *);
+void test_cil_resolve_sidcontext_named_context(CuTest *);
+void test_cil_resolve_sidcontext_named_context_wrongname_neg(CuTest *tc);
+void test_cil_resolve_sidcontext_named_context_invaliduser_neg(CuTest *tc);
+void test_cil_resolve_sidcontext_named_context_sidcontextnull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_sidcontext(CuTest *tc);
+void test_cil_resolve_ast_node_helper_sidcontext_neg(CuTest *tc);
+
+void test_cil_resolve_blockinherit(CuTest *);
+void test_cil_resolve_blockinherit_blockstrdne_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_blockinherit(CuTest *tc);
+
+void test_cil_resolve_in_block(CuTest *);
+void test_cil_resolve_in_blockstrdne_neg(CuTest *);
+void test_cil_resolve_in_macro(CuTest *);
+void test_cil_resolve_in_optional(CuTest *);
+
+void test_cil_resolve_call1_noparam(CuTest *);
+void test_cil_resolve_call1_type(CuTest *);
+void test_cil_resolve_call1_role(CuTest *);
+void test_cil_resolve_call1_user(CuTest *);
+void test_cil_resolve_call1_sens(CuTest *);
+void test_cil_resolve_call1_cat(CuTest *);
+void test_cil_resolve_call1_catset(CuTest *);
+void test_cil_resolve_call1_catset_anon(CuTest *);
+void test_cil_resolve_call1_catset_anon_neg(CuTest *);
+void test_cil_resolve_call1_level(CuTest *);
+void test_cil_resolve_call1_class(CuTest *);
+void test_cil_resolve_call1_classmap(CuTest *);
+void test_cil_resolve_call1_permset(CuTest *);
+void test_cil_resolve_call1_permset_anon(CuTest *);
+void test_cil_resolve_call1_classpermset_named(CuTest *);
+void test_cil_resolve_call1_classpermset_anon(CuTest *);
+void test_cil_resolve_call1_classpermset_anon_neg(CuTest *);
+void test_cil_resolve_call1_level(CuTest *);
+void test_cil_resolve_call1_level_anon(CuTest *);
+void test_cil_resolve_call1_level_anon_neg(CuTest *);
+void test_cil_resolve_call1_ipaddr(CuTest *);
+void test_cil_resolve_call1_ipaddr_anon(CuTest *);
+void test_cil_resolve_call1_ipaddr_anon_neg(CuTest *);
+void test_cil_resolve_call1_unknown_neg(CuTest *);
+void test_cil_resolve_call1_unknowncall_neg(CuTest *);
+void test_cil_resolve_call1_extraargs_neg(CuTest *);
+void test_cil_resolve_call1_copy_dup(CuTest *);
+void test_cil_resolve_call1_missing_arg_neg(CuTest *);
+void test_cil_resolve_call1_paramsflavor_neg(CuTest *);
+void test_cil_resolve_call1_unknownflavor_neg(CuTest *);
+
+void test_cil_resolve_call2_type(CuTest *);
+void test_cil_resolve_call2_role(CuTest *);
+void test_cil_resolve_call2_user(CuTest *);
+void test_cil_resolve_call2_sens(CuTest *);
+void test_cil_resolve_call2_cat(CuTest *);
+void test_cil_resolve_call2_catset(CuTest *);
+void test_cil_resolve_call2_catset_anon(CuTest *);
+void test_cil_resolve_call2_permset(CuTest *);
+void test_cil_resolve_call2_permset_anon(CuTest *);
+void test_cil_resolve_call2_classpermset_named(CuTest *);
+void test_cil_resolve_call2_classpermset_anon(CuTest *);
+void test_cil_resolve_call2_class(CuTest *);
+void test_cil_resolve_call2_classmap(CuTest *);
+void test_cil_resolve_call2_level(CuTest *);
+void test_cil_resolve_call2_level_anon(CuTest *);
+void test_cil_resolve_call2_ipaddr(CuTest *);
+void test_cil_resolve_call2_ipaddr_anon(CuTest *);
+void test_cil_resolve_call2_unknown_neg(CuTest *);
+
+void test_cil_resolve_name_call_args(CuTest *);
+void test_cil_resolve_name_call_args_multipleparams(CuTest *);
+void test_cil_resolve_name_call_args_diffflavor(CuTest *);
+void test_cil_resolve_name_call_args_callnull_neg(CuTest *);
+void test_cil_resolve_name_call_args_namenull_neg(CuTest *);
+void test_cil_resolve_name_call_args_callargsnull_neg(CuTest *);
+void test_cil_resolve_name_call_args_name_neg(CuTest *);
+
+void test_cil_resolve_expr_stack_bools(CuTest *);
+void test_cil_resolve_expr_stack_tunables(CuTest *);
+void test_cil_resolve_expr_stack_type(CuTest *);
+void test_cil_resolve_expr_stack_role(CuTest *);
+void test_cil_resolve_expr_stack_user(CuTest *);
+void test_cil_resolve_expr_stack_neg(CuTest *);
+void test_cil_resolve_expr_stack_emptystr_neg(CuTest *);
+
+void test_cil_resolve_boolif(CuTest *);
+void test_cil_resolve_boolif_neg(CuTest *);
+
+void test_cil_evaluate_expr_stack_and(CuTest *);
+void test_cil_evaluate_expr_stack_not(CuTest *);
+void test_cil_evaluate_expr_stack_or(CuTest *);
+void test_cil_evaluate_expr_stack_xor(CuTest *);
+void test_cil_evaluate_expr_stack_eq(CuTest *);
+void test_cil_evaluate_expr_stack_neq(CuTest *);
+void test_cil_evaluate_expr_stack_oper1(CuTest *);
+void test_cil_evaluate_expr_stack_oper2(CuTest *);
+void test_cil_evaluate_expr_stack_neg(CuTest *);
+
+void test_cil_resolve_tunif_false(CuTest *);
+void test_cil_resolve_tunif_true(CuTest *);
+void test_cil_resolve_tunif_resolveexpr_neg(CuTest *);
+void test_cil_resolve_tunif_evaluateexpr_neg(CuTest *);
+
+void test_cil_resolve_userbounds(CuTest *tc);
+void test_cil_resolve_userbounds_exists_neg(CuTest *tc);
+void test_cil_resolve_userbounds_user1_neg(CuTest *tc);
+void test_cil_resolve_userbounds_user2_neg(CuTest *tc);
+
+void test_cil_resolve_roletype(CuTest *tc);
+void test_cil_resolve_roletype_type_neg(CuTest *tc);
+void test_cil_resolve_roletype_role_neg(CuTest *tc);
+
+void test_cil_resolve_userrole(CuTest *tc);
+void test_cil_resolve_userrole_user_neg(CuTest *tc);
+void test_cil_resolve_userrole_role_neg(CuTest *tc);
+
+void test_cil_resolve_userlevel(CuTest *tc);
+void test_cil_resolve_userlevel_macro(CuTest *tc);
+void test_cil_resolve_userlevel_macro_neg(CuTest *tc);
+void test_cil_resolve_userlevel_level_anon(CuTest *tc);
+void test_cil_resolve_userlevel_level_anon_neg(CuTest *tc);
+void test_cil_resolve_userlevel_user_neg(CuTest *tc);
+void test_cil_resolve_userlevel_level_neg(CuTest *tc);
+
+void test_cil_resolve_userrange(CuTest *tc);
+void test_cil_resolve_userrange_macro(CuTest *tc);
+void test_cil_resolve_userrange_macro_neg(CuTest *tc);
+void test_cil_resolve_userrange_range_anon(CuTest *tc);
+void test_cil_resolve_userrange_range_anon_neg(CuTest *tc);
+void test_cil_resolve_userrange_user_neg(CuTest *tc);
+void test_cil_resolve_userrange_range_neg(CuTest *tc);
+
+void test_cil_disable_children_helper_optional_enabled(CuTest *tc);
+void test_cil_disable_children_helper_optional_disabled(CuTest *tc);
+void test_cil_disable_children_helper_block(CuTest *tc);
+void test_cil_disable_children_helper_user(CuTest *tc);
+void test_cil_disable_children_helper_role(CuTest *tc);
+void test_cil_disable_children_helper_type(CuTest *tc);
+void test_cil_disable_children_helper_typealias(CuTest *tc);
+void test_cil_disable_children_helper_common(CuTest *tc);
+void test_cil_disable_children_helper_class(CuTest *tc);
+void test_cil_disable_children_helper_bool(CuTest *tc);
+void test_cil_disable_children_helper_sens(CuTest *tc);
+void test_cil_disable_children_helper_cat(CuTest *tc);
+void test_cil_disable_children_helper_catset(CuTest *tc);
+void test_cil_disable_children_helper_sid(CuTest *tc);
+void test_cil_disable_children_helper_macro(CuTest *tc);
+void test_cil_disable_children_helper_context(CuTest *tc);
+void test_cil_disable_children_helper_level(CuTest *tc);
+void test_cil_disable_children_helper_policycap(CuTest *tc);
+void test_cil_disable_children_helper_perm(CuTest *tc);
+void test_cil_disable_children_helper_catalias(CuTest *tc);
+void test_cil_disable_children_helper_sensalias(CuTest *tc);
+void test_cil_disable_children_helper_tunable(CuTest *tc);
+void test_cil_disable_children_helper_unknown(CuTest *tc);
+
+/*
+ __cil_resolve_ast_node_helper test cases
+*/
+
+void test_cil_resolve_ast_node_helper_call1(CuTest *);
+void test_cil_resolve_ast_node_helper_call1_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_call2(CuTest *);
+void test_cil_resolve_ast_node_helper_call2_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_boolif(CuTest *);
+void test_cil_resolve_ast_node_helper_boolif_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_tunif(CuTest *);
+void test_cil_resolve_ast_node_helper_tunif_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catorder(CuTest *);
+void test_cil_resolve_ast_node_helper_catorder_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_dominance(CuTest *);
+void test_cil_resolve_ast_node_helper_dominance_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_roleallow(CuTest *);
+void test_cil_resolve_ast_node_helper_roleallow_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_rolebounds(CuTest *tc);
+void test_cil_resolve_ast_node_helper_rolebounds_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_sensalias(CuTest *);
+void test_cil_resolve_ast_node_helper_sensalias_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catalias(CuTest *);
+void test_cil_resolve_ast_node_helper_catalias_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catset(CuTest *);
+void test_cil_resolve_ast_node_helper_catset_catlist_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_level(CuTest *);
+void test_cil_resolve_ast_node_helper_level_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_levelrange(CuTest *);
+void test_cil_resolve_ast_node_helper_levelrange_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_constrain(CuTest *);
+void test_cil_resolve_ast_node_helper_constrain_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_mlsconstrain(CuTest *);
+void test_cil_resolve_ast_node_helper_mlsconstrain_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_context(CuTest *);
+void test_cil_resolve_ast_node_helper_context_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_catrange(CuTest *tc);
+void test_cil_resolve_ast_node_helper_catrange_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_senscat(CuTest *tc);
+void test_cil_resolve_ast_node_helper_senscat_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_roletransition(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_srcdecl_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_tgtdecl_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_roletransition_resultdecl_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typeattributeset(CuTest *);
+void test_cil_resolve_ast_node_helper_typeattributeset_undef_type_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typealias(CuTest *);
+void test_cil_resolve_ast_node_helper_typealias_notype_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typebounds(CuTest *);
+void test_cil_resolve_ast_node_helper_typebounds_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_typepermissive(CuTest *);
+void test_cil_resolve_ast_node_helper_typepermissive_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_nametypetransition(CuTest *);
+void test_cil_resolve_ast_node_helper_nametypetransition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_rangetransition(CuTest *);
+void test_cil_resolve_ast_node_helper_rangetransition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_avrule(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_src_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_tgt_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_class_nores_neg(CuTest *);
+void test_cil_resolve_ast_node_helper_avrule_datum_null_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_transition(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_transition_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_change(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_change_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_type_rule_member(CuTest *);
+void test_cil_resolve_ast_node_helper_type_rule_member_neg(CuTest *);
+
+void test_cil_resolve_ast_node_helper_userbounds(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userbounds_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_roletype(CuTest *tc);
+void test_cil_resolve_ast_node_helper_roletype_role_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_roletype_type_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userrole(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrole_user_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrole_role_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userlevel(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userlevel_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_userrange(CuTest *tc);
+void test_cil_resolve_ast_node_helper_userrange_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_classcommon(CuTest *tc);
+void test_cil_resolve_ast_node_helper_classcommon_neg(CuTest *tc);
+
+void test_cil_resolve_ast_node_helper_callstack(CuTest *tc);
+void test_cil_resolve_ast_node_helper_call(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optional(CuTest *tc);
+void test_cil_resolve_ast_node_helper_macro(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack_tunable_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optstack_macro_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_nodenull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_extraargsnull_neg(CuTest *tc);
+void test_cil_resolve_ast_node_helper_optfailedtoresolve(CuTest *tc);
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_symtab.c b/libsepol/cil/test/unit/test_cil_symtab.c
new file mode 100644
index 0000000..379149a
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_symtab.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_symtab.h"
+
+#include "../../src/cil_tree.h"
+#include "../../src/cil_symtab.h"
+#include "../../src/cil_internal.h"
+
+void test_cil_symtab_insert(CuTest *tc) {
+ symtab_t *test_symtab = NULL;
+ char* test_name = "test";
+ struct cil_block *test_block = malloc(sizeof(*test_block));
+
+ struct cil_tree_node *test_ast_node;
+ cil_tree_node_init(&test_ast_node);
+
+ struct cil_db *test_db;
+ cil_db_init(&test_db);
+
+ test_ast_node->parent = test_db->ast->root;
+ test_ast_node->line = 1;
+
+ cil_symtab_array_init(test_block->symtab, cil_sym_sizes[CIL_SYM_ARRAY_BLOCK]);
+
+ test_block->is_abstract = 0;
+
+ cil_get_symtab(test_db, test_ast_node->parent, &test_symtab, CIL_SYM_BLOCKS);
+
+ int rc = cil_symtab_insert(test_symtab, (hashtab_key_t)test_name, (struct cil_symtab_datum*)test_block, test_ast_node);
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+}
diff --git a/libsepol/cil/test/unit/test_cil_symtab.h b/libsepol/cil/test/unit/test_cil_symtab.h
new file mode 100644
index 0000000..76053af
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_symtab.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_SYMTAB_H_
+#define TEST_CIL_SYMTAB_H_
+
+#include "CuTest.h"
+
+void test_cil_symtab_insert(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_cil_tree.c b/libsepol/cil/test/unit/test_cil_tree.c
new file mode 100644
index 0000000..8bdc113
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_tree.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_cil_tree.h"
+
+#include "../../src/cil_tree.h"
+
+void test_cil_tree_node_init(CuTest *tc) {
+ struct cil_tree_node *test_node;
+
+ cil_tree_node_init(&test_node);
+
+ CuAssertPtrNotNull(tc, test_node);
+ CuAssertPtrEquals(tc, NULL, test_node->cl_head);
+ CuAssertPtrEquals(tc, NULL, test_node->cl_tail);
+ CuAssertPtrEquals(tc, NULL, test_node->parent);
+ CuAssertPtrEquals(tc, NULL, test_node->data);
+ CuAssertPtrEquals(tc, NULL, test_node->next);
+ CuAssertIntEquals(tc, 0, test_node->flavor);
+ CuAssertIntEquals(tc, 0, test_node->line);
+
+ free(test_node);
+}
+
+void test_cil_tree_init(CuTest *tc) {
+ struct cil_tree *test_tree;
+
+ int rc = cil_tree_init(&test_tree);
+
+ CuAssertIntEquals(tc, SEPOL_OK, rc);
+ CuAssertPtrNotNull(tc, test_tree);
+ CuAssertPtrEquals(tc, NULL, test_tree->root->cl_head);
+ CuAssertPtrEquals(tc, NULL, test_tree->root->cl_tail);
+ CuAssertPtrEquals(tc, NULL, test_tree->root->parent);
+ CuAssertPtrEquals(tc, NULL, test_tree->root->data);
+ CuAssertPtrEquals(tc, NULL, test_tree->root->next);
+ CuAssertIntEquals(tc, 0, test_tree->root->flavor);
+ CuAssertIntEquals(tc, 0, test_tree->root->line);
+
+ free(test_tree);
+}
+
diff --git a/libsepol/cil/test/unit/test_cil_tree.h b/libsepol/cil/test/unit/test_cil_tree.h
new file mode 100644
index 0000000..15c0824
--- /dev/null
+++ b/libsepol/cil/test/unit/test_cil_tree.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_CIL_TREE_H_
+#define TEST_CIL_TREE_H_
+
+#include "CuTest.h"
+
+void test_cil_tree_node_init(CuTest *);
+void test_cil_tree_init(CuTest *);
+
+#endif
diff --git a/libsepol/cil/test/unit/test_integration.c b/libsepol/cil/test/unit/test_integration.c
new file mode 100644
index 0000000..d9cdb46
--- /dev/null
+++ b/libsepol/cil/test/unit/test_integration.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#include <sepol/policydb/policydb.h>
+
+#include "CuTest.h"
+#include "test_integration.h"
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void test_integration(CuTest *tc) {
+ int status = 0, status1 = 0, status2 = 0;
+
+ status = system("./secilc -M -c 24 test/integration.cil &> /dev/null");
+
+ if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGQUIT))
+ printf("Call to system for secilc failed.\n");
+
+ status1 = system("checkpolicy -M -c 24 -o policy.conf.24 test/policy.conf &> /dev/null");
+
+ if (WIFSIGNALED(status1) && (WTERMSIG(status1) == SIGINT || WTERMSIG(status1) == SIGQUIT))
+ printf("Call to checkpolicy failed.\n");
+
+ status2 = system("sediff -q policy.24 \\; policy.conf.24 &> /dev/null");
+
+ if (WIFSIGNALED(status2) && (WTERMSIG(status2) == SIGINT || WTERMSIG(status2) == SIGQUIT))
+ printf("Call to sediff for secilc failed.\n");
+
+ CuAssertIntEquals(tc, 1, WIFEXITED(status));
+ CuAssertIntEquals(tc, 0, WEXITSTATUS(status));
+ CuAssertIntEquals(tc, 1, WIFEXITED(status1));
+ CuAssertIntEquals(tc, 0, WEXITSTATUS(status1));
+ CuAssertIntEquals(tc, 1, WIFEXITED(status2));
+ CuAssertIntEquals(tc, 0, WEXITSTATUS(status2));
+}
+
+void test_min_policy(CuTest *tc) {
+ int status = 0;
+
+ status = system("./secilc -M -c 24 test/policy.cil &> /dev/null");
+
+ if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGQUIT))
+ printf("Call to system for secilc failed.\n");
+
+ CuAssertIntEquals(tc, 1, WIFEXITED(status));
+ CuAssertIntEquals(tc, 0, WEXITSTATUS(status));
+}
diff --git a/libsepol/cil/test/unit/test_integration.h b/libsepol/cil/test/unit/test_integration.h
new file mode 100644
index 0000000..4cbcce3
--- /dev/null
+++ b/libsepol/cil/test/unit/test_integration.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tresys Technology, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those
+ * of the authors and should not be interpreted as representing official policies,
+ * either expressed or implied, of Tresys Technology, LLC.
+ */
+
+#ifndef TEST_INTEGRATION_H
+#define TEST_INTEGRATION_H
+
+#include "CuTest.h"
+
+void test_min_policy(CuTest *);
+void test_integration(CuTest *);
+
+#endif
diff --git a/libsepol/include/Makefile b/libsepol/include/Makefile
new file mode 100644
index 0000000..56b7a11
--- /dev/null
+++ b/libsepol/include/Makefile
@@ -0,0 +1,17 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCDIR ?= $(PREFIX)/include/sepol
+CILDIR ?= ../cil
+
+all:
+
+install: all
+ test -d $(INCDIR) || install -m 755 -d $(INCDIR)
+ test -d $(INCDIR)/policydb || install -m 755 -d $(INCDIR)/policydb
+ test -d $(INCDIR)/cil || install -m 755 -d $(INCDIR)/cil
+ install -m 644 $(wildcard sepol/*.h) $(INCDIR)
+ install -m 644 $(wildcard sepol/policydb/*.h) $(INCDIR)/policydb
+ install -m 644 $(wildcard $(CILDIR)/include/cil/*.h) $(INCDIR)/cil
+
+indent:
+ ../../scripts/Lindent $(wildcard sepol/*.h)
diff --git a/libsepol/include/sepol/boolean_record.h b/libsepol/include/sepol/boolean_record.h
new file mode 100644
index 0000000..9af16be
--- /dev/null
+++ b/libsepol/include/sepol/boolean_record.h
@@ -0,0 +1,55 @@
+#ifndef _SEPOL_BOOLEAN_RECORD_H_
+#define _SEPOL_BOOLEAN_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_bool;
+struct sepol_bool_key;
+typedef struct sepol_bool sepol_bool_t;
+typedef struct sepol_bool_key sepol_bool_key_t;
+
+/* Key */
+extern int sepol_bool_key_create(sepol_handle_t * handle,
+ const char *name, sepol_bool_key_t ** key);
+
+extern void sepol_bool_key_unpack(const sepol_bool_key_t * key,
+ const char **name);
+
+extern int sepol_bool_key_extract(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_key_t ** key_ptr);
+
+extern void sepol_bool_key_free(sepol_bool_key_t * key);
+
+extern int sepol_bool_compare(const sepol_bool_t * boolean,
+ const sepol_bool_key_t * key);
+
+extern int sepol_bool_compare2(const sepol_bool_t * boolean,
+ const sepol_bool_t * boolean2);
+
+/* Name */
+extern const char *sepol_bool_get_name(const sepol_bool_t * boolean);
+
+extern int sepol_bool_set_name(sepol_handle_t * handle,
+ sepol_bool_t * boolean, const char *name);
+
+/* Value */
+extern int sepol_bool_get_value(const sepol_bool_t * boolean);
+
+extern void sepol_bool_set_value(sepol_bool_t * boolean, int value);
+
+/* Create/Clone/Destroy */
+extern int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr);
+
+extern int sepol_bool_clone(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_t ** bool_ptr);
+
+extern void sepol_bool_free(sepol_bool_t * boolean);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/booleans.h b/libsepol/include/sepol/booleans.h
new file mode 100644
index 0000000..7374dde
--- /dev/null
+++ b/libsepol/include/sepol/booleans.h
@@ -0,0 +1,63 @@
+#ifndef _SEPOL_BOOLEANS_H_
+#define _SEPOL_BOOLEANS_H_
+
+#include <stddef.h>
+#include <sepol/policydb.h>
+#include <sepol/boolean_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*--------------compatibility--------------*/
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+ and a boolean configuration file named by 'boolpath', rewrite the binary
+ policy for the boolean settings in the boolean configuration file.
+ The binary policy is rewritten in place in memory.
+ Returns 0 upon success, or -1 otherwise. */
+extern int sepol_genbools(void *data, size_t len, char *boolpath);
+
+/* Given an existing binary policy (starting at 'data', with length 'len')
+ and boolean settings specified by the parallel arrays ('names', 'values')
+ with 'nel' elements, rewrite the binary policy for the boolean settings.
+ The binary policy is rewritten in place in memory.
+ Returns 0 upon success or -1 otherwise. */
+extern int sepol_genbools_array(void *data, size_t len,
+ char **names, int *values, int nel);
+/*---------------end compatbility------------*/
+
+/* Set the specified boolean */
+extern int sepol_bool_set(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_bool_key_t * key,
+ const sepol_bool_t * data);
+
+/* Return the number of booleans */
+extern int sepol_bool_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified boolean exists */
+extern int sepol_bool_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_bool_key_t * key, int *response);
+
+/* Query a boolean - returns the boolean, or NULL if not found */
+extern int sepol_bool_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key,
+ sepol_bool_t ** response);
+
+/* Iterate the booleans
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_bool_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_bool_t * boolean,
+ void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/context.h b/libsepol/include/sepol/context.h
new file mode 100644
index 0000000..a69e8c9
--- /dev/null
+++ b/libsepol/include/sepol/context.h
@@ -0,0 +1,30 @@
+#ifndef _SEPOL_CONTEXT_H_
+#define _SEPOL_CONTEXT_H_
+
+#include <sepol/context_record.h>
+#include <sepol/policydb.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* -- Deprecated -- */
+
+extern int sepol_check_context(const char *context);
+
+/* -- End deprecated -- */
+
+extern int sepol_context_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_context_t * context);
+
+extern int sepol_mls_contains(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const char *mls1,
+ const char *mls2, int *response);
+
+extern int sepol_mls_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb, const char *mls);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/context_record.h b/libsepol/include/sepol/context_record.h
new file mode 100644
index 0000000..c07da8f
--- /dev/null
+++ b/libsepol/include/sepol/context_record.h
@@ -0,0 +1,57 @@
+#ifndef _SEPOL_CONTEXT_RECORD_H_
+#define _SEPOL_CONTEXT_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_context;
+typedef struct sepol_context sepol_context_t;
+
+/* We don't need a key, because the context is never stored
+ * in a data collection by itself */
+
+/* User */
+extern const char *sepol_context_get_user(const sepol_context_t * con);
+
+extern int sepol_context_set_user(sepol_handle_t * handle,
+ sepol_context_t * con, const char *user);
+
+/* Role */
+extern const char *sepol_context_get_role(const sepol_context_t * con);
+
+extern int sepol_context_set_role(sepol_handle_t * handle,
+ sepol_context_t * con, const char *role);
+
+/* Type */
+extern const char *sepol_context_get_type(const sepol_context_t * con);
+
+extern int sepol_context_set_type(sepol_handle_t * handle,
+ sepol_context_t * con, const char *type);
+
+/* MLS */
+extern const char *sepol_context_get_mls(const sepol_context_t * con);
+
+extern int sepol_context_set_mls(sepol_handle_t * handle,
+ sepol_context_t * con, const char *mls_range);
+
+/* Create/Clone/Destroy */
+extern int sepol_context_create(sepol_handle_t * handle,
+ sepol_context_t ** con_ptr);
+
+extern int sepol_context_clone(sepol_handle_t * handle,
+ const sepol_context_t * con,
+ sepol_context_t ** con_ptr);
+
+extern void sepol_context_free(sepol_context_t * con);
+
+/* Parse to/from string */
+extern int sepol_context_from_string(sepol_handle_t * handle,
+ const char *str, sepol_context_t ** con);
+
+extern int sepol_context_to_string(sepol_handle_t * handle,
+ const sepol_context_t * con, char **str_ptr);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/debug.h b/libsepol/include/sepol/debug.h
new file mode 100644
index 0000000..b852c8d
--- /dev/null
+++ b/libsepol/include/sepol/debug.h
@@ -0,0 +1,39 @@
+#ifndef _SEPOL_DEBUG_H_
+#define _SEPOL_DEBUG_H_
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Deprecated */
+extern void sepol_debug(int on);
+/* End deprecated */
+
+#define SEPOL_MSG_ERR 1
+#define SEPOL_MSG_WARN 2
+#define SEPOL_MSG_INFO 3
+
+extern int sepol_msg_get_level(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_channel(sepol_handle_t * handle);
+
+extern const char *sepol_msg_get_fname(sepol_handle_t * handle);
+
+/* Set the messaging callback.
+ * By the default, the callback will print
+ * the message on standard output, in a
+ * particular format. Passing NULL here
+ * indicates that messaging should be suppressed */
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t *
+ handle,
+ const char *fmt, ...),
+ void *msg_callback_arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/errcodes.h b/libsepol/include/sepol/errcodes.h
new file mode 100644
index 0000000..eba7088
--- /dev/null
+++ b/libsepol/include/sepol/errcodes.h
@@ -0,0 +1,29 @@
+/* Author: Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_errno_h__
+#define __sepol_errno_h__
+
+#include <errno.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define SEPOL_OK 0
+
+/* These first error codes are defined for compatibility with
+ * previous version of libsepol. In the future, custome error
+ * codes that don't map to system error codes should be defined
+ * outside of the range of system error codes.
+ */
+#define SEPOL_ERR -1
+#define SEPOL_ENOTSUP -2 /* feature not supported in module language */
+#define SEPOL_EREQ -3 /* requirements not met */
+
+/* Error codes that map to system error codes */
+#define SEPOL_ENOMEM -ENOMEM
+#define SEPOL_ERANGE -ERANGE
+#define SEPOL_EEXIST -EEXIST
+#define SEPOL_ENOENT -ENOENT
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/handle.h b/libsepol/include/sepol/handle.h
new file mode 100644
index 0000000..00ed0ed
--- /dev/null
+++ b/libsepol/include/sepol/handle.h
@@ -0,0 +1,39 @@
+#ifndef _SEPOL_HANDLE_H_
+#define _SEPOL_HANDLE_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_handle;
+typedef struct sepol_handle sepol_handle_t;
+
+/* Create and return a sepol handle. */
+sepol_handle_t *sepol_handle_create(void);
+
+/* Get whether or not dontaudits will be disabled, same values as
+ * specified by set_disable_dontaudit. This value reflects the state
+ * your system will be set to upon commit, not necessarily its
+ * current state.*/
+int sepol_get_disable_dontaudit(sepol_handle_t * sh);
+
+/* Set whether or not to disable dontaudits, 0 is default and does
+ * not disable dontaudits, 1 disables them */
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit);
+
+/* Set whether module_expand() should consume the base policy passed in.
+ * This should reduce the amount of memory required to expand the policy. */
+void sepol_set_expand_consume_base(sepol_handle_t * sh, int consume_base);
+
+/* Destroy a sepol handle. */
+void sepol_handle_destroy(sepol_handle_t *);
+
+/* Get whether or not needless unused branch of tunables would be preserved */
+int sepol_get_preserve_tunables(sepol_handle_t * sh);
+
+/* Set whether or not to preserve the needless unused branch of tunables,
+ * 0 is default and discard such branch, 1 preserves them */
+void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/iface_record.h b/libsepol/include/sepol/iface_record.h
new file mode 100644
index 0000000..81d7027
--- /dev/null
+++ b/libsepol/include/sepol/iface_record.h
@@ -0,0 +1,63 @@
+#ifndef _SEPOL_IFACE_RECORD_H_
+#define _SEPOL_IFACE_RECORD_H_
+
+#include <sepol/handle.h>
+#include <sepol/context_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_iface;
+struct sepol_iface_key;
+typedef struct sepol_iface sepol_iface_t;
+typedef struct sepol_iface_key sepol_iface_key_t;
+
+/* Key */
+extern int sepol_iface_compare(const sepol_iface_t * iface,
+ const sepol_iface_key_t * key);
+
+extern int sepol_iface_compare2(const sepol_iface_t * iface,
+ const sepol_iface_t * iface2);
+
+extern void sepol_iface_key_unpack(const sepol_iface_key_t * key,
+ const char **name);
+
+extern int sepol_iface_key_create(sepol_handle_t * handle,
+ const char *name,
+ sepol_iface_key_t ** key_ptr);
+
+extern int sepol_iface_key_extract(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_key_t ** key_ptr);
+
+extern void sepol_iface_key_free(sepol_iface_key_t * key);
+
+/* Name */
+extern const char *sepol_iface_get_name(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_name(sepol_handle_t * handle,
+ sepol_iface_t * iface, const char *name);
+
+/* Context */
+extern sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_ifcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con);
+
+extern sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface);
+
+extern int sepol_iface_set_msgcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_iface_create(sepol_handle_t * handle,
+ sepol_iface_t ** iface_ptr);
+
+extern int sepol_iface_clone(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_t ** iface_ptr);
+
+extern void sepol_iface_free(sepol_iface_t * iface);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/interfaces.h b/libsepol/include/sepol/interfaces.h
new file mode 100644
index 0000000..3cb5043
--- /dev/null
+++ b/libsepol/include/sepol/interfaces.h
@@ -0,0 +1,47 @@
+#ifndef __SEPOL_INTERFACES_H_
+#define __SEPOL_INTERFACES_H_
+
+#include <sepol/policydb.h>
+#include <sepol/iface_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ unsigned int *response);
+
+/* Check if an interface exists */
+extern int sepol_iface_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key, int *response);
+
+/* Query an interface - returns the interface,
+ * or NULL if not found */
+extern int sepol_iface_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key,
+ sepol_iface_t ** response);
+
+/* Modify an interface, or add it, if the key
+ * is not found */
+extern int sepol_iface_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_iface_key_t * key,
+ const sepol_iface_t * data);
+
+/* Iterate the interfaces
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_iface_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_iface_t * iface,
+ void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/module.h b/libsepol/include/sepol/module.h
new file mode 100644
index 0000000..ff27f96
--- /dev/null
+++ b/libsepol/include/sepol/module.h
@@ -0,0 +1,86 @@
+#ifndef _SEPOL_MODULE_H_
+#define _SEPOL_MODULE_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_module_package;
+typedef struct sepol_module_package sepol_module_package_t;
+
+/* Module package public interfaces. */
+
+extern int sepol_module_package_create(sepol_module_package_t ** p);
+
+extern void sepol_module_package_free(sepol_module_package_t * p);
+
+extern char *sepol_module_package_get_file_contexts(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t
+ * p);
+
+extern int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_seusers(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_seusers(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_user_extra(sepol_module_package_t * p);
+
+extern size_t sepol_module_package_get_user_extra_len(sepol_module_package_t *
+ p);
+
+extern int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+ char *data, size_t len);
+
+extern char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t
+ * p);
+
+extern size_t
+sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p);
+
+extern int sepol_module_package_set_netfilter_contexts(sepol_module_package_t *
+ p, char *data,
+ size_t len);
+
+extern sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t
+ * p);
+
+extern int sepol_link_packages(sepol_handle_t * handle,
+ sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules, int verbose);
+
+extern int sepol_module_package_read(sepol_module_package_t * mod,
+ struct sepol_policy_file *file,
+ int verbose);
+
+extern int sepol_module_package_info(struct sepol_policy_file *file,
+ int *type, char **name, char **version);
+
+extern int sepol_module_package_write(sepol_module_package_t * p,
+ struct sepol_policy_file *file);
+
+/* Module linking/expanding public interfaces. */
+
+extern int sepol_link_modules(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t ** modules,
+ size_t len, int verbose);
+
+extern int sepol_expand_module(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t * out, int verbose, int check);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/module_to_cil.h b/libsepol/include/sepol/module_to_cil.h
new file mode 100644
index 0000000..18bb3bf
--- /dev/null
+++ b/libsepol/include/sepol/module_to_cil.h
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+#include <sepol/module.h>
+#include <sepol/policydb/policydb.h>
+
+int sepol_module_policydb_to_cil(FILE *fp, struct policydb *pdb, int linked);
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg);
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg);
diff --git a/libsepol/include/sepol/node_record.h b/libsepol/include/sepol/node_record.h
new file mode 100644
index 0000000..e2d3e6d
--- /dev/null
+++ b/libsepol/include/sepol/node_record.h
@@ -0,0 +1,96 @@
+#ifndef _SEPOL_NODE_RECORD_H_
+#define _SEPOL_NODE_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_node;
+struct sepol_node_key;
+typedef struct sepol_node sepol_node_t;
+typedef struct sepol_node_key sepol_node_key_t;
+
+#define SEPOL_PROTO_IP4 0
+#define SEPOL_PROTO_IP6 1
+
+/* Key */
+extern int sepol_node_compare(const sepol_node_t * node,
+ const sepol_node_key_t * key);
+
+extern int sepol_node_compare2(const sepol_node_t * node,
+ const sepol_node_t * node2);
+
+extern int sepol_node_key_create(sepol_handle_t * handle,
+ const char *addr,
+ const char *mask,
+ int proto, sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_unpack(const sepol_node_key_t * key,
+ const char **addr,
+ const char **mask, int *proto);
+
+extern int sepol_node_key_extract(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_key_t ** key_ptr);
+
+extern void sepol_node_key_free(sepol_node_key_t * key);
+
+/* Address */
+extern int sepol_node_get_addr(sepol_handle_t * handle,
+ const sepol_node_t * node, char **addr);
+
+extern int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **addr, size_t * addr_sz);
+
+extern int sepol_node_set_addr(sepol_handle_t * handle,
+ sepol_node_t * node,
+ int proto, const char *addr);
+
+extern int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *addr, size_t addr_sz);
+
+/* Netmask */
+extern int sepol_node_get_mask(sepol_handle_t * handle,
+ const sepol_node_t * node, char **mask);
+
+extern int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **mask, size_t * mask_sz);
+
+extern int sepol_node_set_mask(sepol_handle_t * handle,
+ sepol_node_t * node,
+ int proto, const char *mask);
+
+extern int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *mask, size_t mask_sz);
+
+/* Protocol */
+extern int sepol_node_get_proto(const sepol_node_t * node);
+
+extern void sepol_node_set_proto(sepol_node_t * node, int proto);
+
+extern const char *sepol_node_get_proto_str(int proto);
+
+/* Context */
+extern sepol_context_t *sepol_node_get_con(const sepol_node_t * node);
+
+extern int sepol_node_set_con(sepol_handle_t * handle,
+ sepol_node_t * node, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node_ptr);
+
+extern int sepol_node_clone(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_t ** node_ptr);
+
+extern void sepol_node_free(sepol_node_t * node);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/nodes.h b/libsepol/include/sepol/nodes.h
new file mode 100644
index 0000000..6fa534e
--- /dev/null
+++ b/libsepol/include/sepol/nodes.h
@@ -0,0 +1,44 @@
+#ifndef _SEPOL_NODES_H_
+#define _SEPOL_NODES_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/node_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a node exists */
+extern int sepol_node_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_node_key_t * key, int *response);
+
+/* Query a node - returns the node, or NULL if not found */
+extern int sepol_node_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_node_key_t * key,
+ sepol_node_t ** response);
+
+/* Modify a node, or add it, if the key is not found */
+extern int sepol_node_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_node_key_t * key,
+ const sepol_node_t * data);
+
+/* Iterate the nodes
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_node_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_node_t * node,
+ void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb.h b/libsepol/include/sepol/policydb.h
new file mode 100644
index 0000000..c3943e9
--- /dev/null
+++ b/libsepol/include/sepol/policydb.h
@@ -0,0 +1,148 @@
+#ifndef _SEPOL_POLICYDB_H_
+#define _SEPOL_POLICYDB_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_policy_file;
+typedef struct sepol_policy_file sepol_policy_file_t;
+
+struct sepol_policydb;
+typedef struct sepol_policydb sepol_policydb_t;
+
+/* Policy file public interfaces. */
+
+/* Create and free memory associated with a policy file. */
+extern int sepol_policy_file_create(sepol_policy_file_t ** pf);
+extern void sepol_policy_file_free(sepol_policy_file_t * pf);
+
+/*
+ * Set the policy file to represent a binary policy memory image.
+ * Subsequent operations using the policy file will read and write
+ * the image located at the specified address with the specified length.
+ * If 'len' is 0, then merely compute the necessary length upon
+ * subsequent policydb write operations in order to determine the
+ * necessary buffer size to allocate.
+ */
+extern void sepol_policy_file_set_mem(sepol_policy_file_t * pf,
+ char *data, size_t len);
+
+/*
+ * Get the size of the buffer needed to store a policydb write
+ * previously done on this policy file.
+ */
+extern int sepol_policy_file_get_len(sepol_policy_file_t * pf, size_t * len);
+
+/*
+ * Set the policy file to represent a FILE.
+ * Subsequent operations using the policy file will read and write
+ * to the FILE.
+ */
+extern void sepol_policy_file_set_fp(sepol_policy_file_t * pf, FILE * fp);
+
+/*
+ * Associate a handle with a policy file, for use in
+ * error reporting from subsequent calls that take the
+ * policy file as an argument.
+ */
+extern void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+ sepol_handle_t * handle);
+
+/* Policydb public interfaces. */
+
+/* Create and free memory associated with a policydb. */
+extern int sepol_policydb_create(sepol_policydb_t ** p);
+extern void sepol_policydb_free(sepol_policydb_t * p);
+
+/* Legal types of policies that the policydb can represent. */
+#define SEPOL_POLICY_KERN 0
+#define SEPOL_POLICY_BASE 1
+#define SEPOL_POLICY_MOD 2
+
+/*
+ * Range of policy versions for the kernel policy type supported
+ * by this library.
+ */
+extern int sepol_policy_kern_vers_min(void);
+extern int sepol_policy_kern_vers_max(void);
+
+/*
+ * Set the policy type as specified, and automatically initialize the
+ * policy version accordingly to the maximum version supported for the
+ * policy type.
+ * Returns -1 if the policy type is not legal.
+ */
+extern int sepol_policydb_set_typevers(sepol_policydb_t * p, unsigned int type);
+
+/*
+ * Set the policy version to a different value.
+ * Returns -1 if the policy version is not in the supported range for
+ * the (previously set) policy type.
+ */
+extern int sepol_policydb_set_vers(sepol_policydb_t * p, unsigned int vers);
+
+/* Set how to handle unknown class/perms. */
+#define SEPOL_DENY_UNKNOWN 0
+#define SEPOL_REJECT_UNKNOWN 2
+#define SEPOL_ALLOW_UNKNOWN 4
+extern int sepol_policydb_set_handle_unknown(sepol_policydb_t * p,
+ unsigned int handle_unknown);
+
+/* Set the target platform */
+#define SEPOL_TARGET_SELINUX 0
+#define SEPOL_TARGET_XEN 1
+extern int sepol_policydb_set_target_platform(sepol_policydb_t * p,
+ int target_platform);
+
+/*
+ * Read a policydb from a policy file.
+ * This automatically sets the type and version based on the
+ * image contents.
+ */
+extern int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Write a policydb to a policy file.
+ * The generated image will be in the binary format corresponding
+ * to the policy version associated with the policydb.
+ */
+extern int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf);
+
+/*
+ * Extract a policydb from a binary policy memory image.
+ * This is equivalent to sepol_policydb_read with a policy file
+ * set to refer to memory.
+ */
+extern int sepol_policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len,
+ sepol_policydb_t * p);
+
+/*
+ * Generate a binary policy memory image from a policydb.
+ * This is equivalent to sepol_policydb_write with a policy file
+ * set to refer to memory, but internally handles computing the
+ * necessary length and allocating an appropriately sized memory
+ * buffer for the caller.
+ */
+extern int sepol_policydb_to_image(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ void **newdata, size_t * newlen);
+
+/*
+ * Check whether the policydb has MLS enabled.
+ */
+extern int sepol_policydb_mls_enabled(const sepol_policydb_t * p);
+
+/*
+ * Check whether the compatibility mode for SELinux network
+ * checks should be enabled when using this policy.
+ */
+extern int sepol_policydb_compat_net(const sepol_policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/avrule_block.h b/libsepol/include/sepol/policydb/avrule_block.h
new file mode 100644
index 0000000..ecd347b
--- /dev/null
+++ b/libsepol/include/sepol/policydb/avrule_block.h
@@ -0,0 +1,41 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_AVRULE_BLOCK_H_
+#define _SEPOL_AVRULE_BLOCK_H_
+
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern avrule_block_t *avrule_block_create(void);
+extern void avrule_block_destroy(avrule_block_t * x);
+extern avrule_decl_t *avrule_decl_create(uint32_t decl_id);
+extern void avrule_decl_destroy(avrule_decl_t * x);
+extern void avrule_block_list_destroy(avrule_block_t * x);
+extern avrule_decl_t *get_avrule_decl(policydb_t * p, uint32_t decl_id);
+extern cond_list_t *get_decl_cond_list(policydb_t * p,
+ avrule_decl_t * decl,
+ cond_list_t * cond);
+extern int is_id_enabled(char *id, policydb_t * p, int symbol_table);
+extern int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
new file mode 100644
index 0000000..d3ea84e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/avtab.h
@@ -0,0 +1,148 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * An access vector table (avtab) is a hash table
+ * of access vectors and transition types indexed
+ * by a type pair and a class. An access vector
+ * table is used to represent the type enforcement
+ * tables.
+ */
+
+#ifndef _SEPOL_POLICYDB_AVTAB_H_
+#define _SEPOL_POLICYDB_AVTAB_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+typedef struct avtab_key {
+ uint16_t source_type;
+ uint16_t target_type;
+ uint16_t target_class;
+#define AVTAB_ALLOWED 0x0001
+#define AVTAB_AUDITALLOW 0x0002
+#define AVTAB_AUDITDENY 0x0004
+#define AVTAB_NEVERALLOW 0x0080
+#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 0x0010
+#define AVTAB_MEMBER 0x0020
+#define AVTAB_CHANGE 0x0040
+#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_XPERMS_ALLOWED 0x0100
+#define AVTAB_XPERMS_AUDITALLOW 0x0200
+#define AVTAB_XPERMS_DONTAUDIT 0x0400
+#define AVTAB_XPERMS_NEVERALLOW 0x0800
+#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | AVTAB_XPERMS_DONTAUDIT)
+#define AVTAB_ENABLED_OLD 0x80000000
+#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
+ uint16_t specified; /* what fields are specified */
+} avtab_key_t;
+
+typedef struct avtab_extended_perms {
+
+#define AVTAB_XPERMS_IOCTLFUNCTION 0x01
+#define AVTAB_XPERMS_IOCTLDRIVER 0x02
+ /* extension of the avtab_key specified */
+ uint8_t specified;
+ uint8_t driver;
+ uint32_t perms[8];
+} avtab_extended_perms_t;
+
+typedef struct avtab_datum {
+ uint32_t data; /* access vector or type */
+ avtab_extended_perms_t *xperms;
+} avtab_datum_t;
+
+typedef struct avtab_node *avtab_ptr_t;
+
+struct avtab_node {
+ avtab_key_t key;
+ avtab_datum_t datum;
+ avtab_ptr_t next;
+ void *parse_context; /* generic context pointer used by parser;
+ * not saved in binary policy */
+ unsigned merged; /* flag for avtab_write only;
+ not saved in binary policy */
+};
+
+typedef struct avtab {
+ avtab_ptr_t *htable;
+ uint32_t nel; /* number of elements */
+ uint32_t nslot; /* number of hash slots */
+ uint32_t mask; /* mask to compute hash func */
+} avtab_t;
+
+extern int avtab_init(avtab_t *);
+extern int avtab_alloc(avtab_t *, uint32_t);
+extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
+
+extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
+
+extern void avtab_destroy(avtab_t * h);
+
+extern int avtab_map(avtab_t * h,
+ int (*apply) (avtab_key_t * k,
+ avtab_datum_t * d, void *args), void *args);
+
+extern void avtab_hash_eval(avtab_t * h, char *tag);
+
+struct policy_file;
+extern int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+ int (*insert) (avtab_t * a, avtab_key_t * k,
+ avtab_datum_t * d, void *p), void *p);
+
+extern int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers);
+
+extern avtab_ptr_t avtab_insert_nonunique(avtab_t * h, avtab_key_t * key,
+ avtab_datum_t * datum);
+
+extern avtab_ptr_t avtab_insert_with_parse_context(avtab_t * h,
+ avtab_key_t * key,
+ avtab_datum_t * datum,
+ void *parse_context);
+
+extern avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key);
+
+extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
+
+#define MAX_AVTAB_HASH_BITS 20
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+/* avtab_alloc uses one bucket per 2-4 elements, so adjust to get maximum buckets */
+#define MAX_AVTAB_SIZE (MAX_AVTAB_HASH_BUCKETS << 1)
+
+__END_DECLS
+#endif /* _AVTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/conditional.h b/libsepol/include/sepol/policydb/conditional.h
new file mode 100644
index 0000000..cd2a9a9
--- /dev/null
+++ b/libsepol/include/sepol/policydb/conditional.h
@@ -0,0 +1,140 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ * Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_CONDITIONAL_H_
+#define _SEPOL_POLICYDB_CONDITIONAL_H_
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define COND_EXPR_MAXDEPTH 10
+
+/* this is the max unique bools in a conditional expression
+ * for which we precompute all outcomes for the expression.
+ *
+ * NOTE - do _NOT_ use value greater than 5 because
+ * cond_node_t->expr_pre_comp can only hold at most 32 values
+ */
+#define COND_MAX_BOOLS 5
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+typedef struct cond_expr {
+#define COND_BOOL 1 /* plain bool */
+#define COND_NOT 2 /* !bool */
+#define COND_OR 3 /* bool || bool */
+#define COND_AND 4 /* bool && bool */
+#define COND_XOR 5 /* bool ^ bool */
+#define COND_EQ 6 /* bool == bool */
+#define COND_NEQ 7 /* bool != bool */
+#define COND_LAST COND_NEQ
+ uint32_t expr_type;
+ uint32_t bool;
+ struct cond_expr *next;
+} cond_expr_t;
+
+/*
+ * Each cond_node_t contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This
+ * struct is for that list.
+ */
+typedef struct cond_av_list {
+ avtab_ptr_t node;
+ struct cond_av_list *next;
+} cond_av_list_t;
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+typedef struct cond_node {
+ int cur_state;
+ cond_expr_t *expr;
+ /* these true/false lists point into te_avtab when that is used */
+ cond_av_list_t *true_list;
+ cond_av_list_t *false_list;
+ /* and these are used during parsing and for modules */
+ avrule_t *avtrue_list;
+ avrule_t *avfalse_list;
+ /* these fields are not written to binary policy */
+ unsigned int nbools;
+ uint32_t bool_ids[COND_MAX_BOOLS];
+ uint32_t expr_pre_comp;
+ struct cond_node *next;
+ /* a tunable conditional, calculated and used at expansion */
+#define COND_NODE_FLAGS_TUNABLE 0x01
+ uint32_t flags;
+} cond_node_t;
+
+extern int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr);
+extern cond_expr_t *cond_copy_expr(cond_expr_t * expr);
+
+extern int cond_expr_equal(cond_node_t * a, cond_node_t * b);
+extern int cond_normalize_expr(policydb_t * p, cond_node_t * cn);
+extern void cond_node_destroy(cond_node_t * node);
+extern void cond_expr_destroy(cond_expr_t * expr);
+
+extern cond_node_t *cond_node_find(policydb_t * p,
+ cond_node_t * needle, cond_node_t * haystack,
+ int *was_created);
+
+extern cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node);
+
+extern cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+ cond_node_t * cn);
+
+extern int evaluate_conds(policydb_t * p);
+
+extern avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+ cond_av_list_t * cond_list);
+
+extern void cond_av_list_destroy(cond_av_list_t * list);
+
+extern void cond_optimize_lists(cond_list_t * cl);
+
+extern int cond_policydb_init(policydb_t * p);
+extern void cond_policydb_destroy(policydb_t * p);
+extern void cond_list_destroy(cond_list_t * list);
+
+extern int cond_init_bool_indexes(policydb_t * p);
+extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
+
+extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum,
+ void *datap);
+
+extern int cond_read_bool(policydb_t * p, hashtab_t h, struct policy_file *fp);
+
+extern int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp);
+
+extern void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+ struct sepol_av_decision *avd);
+
+__END_DECLS
+#endif /* _CONDITIONAL_H_ */
diff --git a/libsepol/include/sepol/policydb/constraint.h b/libsepol/include/sepol/policydb/constraint.h
new file mode 100644
index 0000000..ae7034d
--- /dev/null
+++ b/libsepol/include/sepol/policydb/constraint.h
@@ -0,0 +1,79 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A constraint is a condition that must be satisfied in
+ * order for one or more permissions to be granted.
+ * Constraints are used to impose additional restrictions
+ * beyond the type-based rules in `te' or the role-based
+ * transition rules in `rbac'. Constraints are typically
+ * used to prevent a process from transitioning to a new user
+ * identity or role unless it is in a privileged type.
+ * Constraints are likewise typically used to prevent a
+ * process from labeling an object with a different user
+ * identity.
+ */
+
+#ifndef _SEPOL_POLICYDB_CONSTRAINT_H_
+#define _SEPOL_POLICYDB_CONSTRAINT_H_
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+
+__BEGIN_DECLS
+
+#define CEXPR_MAXDEPTH 5
+
+struct type_set;
+
+typedef struct constraint_expr {
+#define CEXPR_NOT 1 /* not expr */
+#define CEXPR_AND 2 /* expr and expr */
+#define CEXPR_OR 3 /* expr or expr */
+#define CEXPR_ATTR 4 /* attr op attr */
+#define CEXPR_NAMES 5 /* attr op names */
+ uint32_t expr_type; /* expression type */
+
+#define CEXPR_USER 1 /* user */
+#define CEXPR_ROLE 2 /* role */
+#define CEXPR_TYPE 4 /* type */
+#define CEXPR_TARGET 8 /* target if set, source otherwise */
+#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
+ uint32_t attr; /* attribute */
+
+#define CEXPR_EQ 1 /* == or eq */
+#define CEXPR_NEQ 2 /* != */
+#define CEXPR_DOM 3 /* dom */
+#define CEXPR_DOMBY 4 /* domby */
+#define CEXPR_INCOMP 5 /* incomp */
+ uint32_t op; /* operator */
+
+ ebitmap_t names; /* names */
+ struct type_set *type_names;
+
+ struct constraint_expr *next; /* next expression */
+} constraint_expr_t;
+
+typedef struct constraint_node {
+ sepol_access_vector_t permissions; /* constrained permissions */
+ constraint_expr_t *expr; /* constraint on permissions */
+ struct constraint_node *next; /* next constraint */
+} constraint_node_t;
+
+struct policydb;
+
+extern int constraint_expr_init(constraint_expr_t * expr);
+extern void constraint_expr_destroy(constraint_expr_t * expr);
+
+__END_DECLS
+#endif /* _CONSTRAINT_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/context.h b/libsepol/include/sepol/policydb/context.h
new file mode 100644
index 0000000..dbb7c3e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/context.h
@@ -0,0 +1,99 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy. Security contexts are
+ * externally represented as variable-length strings
+ * that can be interpreted by a user or application
+ * with an understanding of the security policy.
+ * Internally, the security server uses a simple
+ * structure. This structure is private to the
+ * security server and can be changed without affecting
+ * clients of the security server.
+ */
+
+#ifndef _SEPOL_POLICYDB_CONTEXT_H_
+#define _SEPOL_POLICYDB_CONTEXT_H_
+
+#include <stddef.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/mls_types.h>
+
+__BEGIN_DECLS
+
+/*
+ * A security context consists of an authenticated user
+ * identity, a role, a type and a MLS range.
+ */
+typedef struct context_struct {
+ uint32_t user;
+ uint32_t role;
+ uint32_t type;
+ mls_range_t range;
+} context_struct_t;
+
+static inline void mls_context_init(context_struct_t * c)
+{
+ mls_range_init(&c->range);
+}
+
+static inline int mls_context_cpy(context_struct_t * dst,
+ context_struct_t * src)
+{
+
+ if (mls_range_cpy(&dst->range, &src->range) < 0)
+ return -1;
+
+ return 0;
+}
+
+static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+ return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) &&
+ mls_level_eq(&c1->range.level[1], &c2->range.level[1]));
+
+}
+
+static inline void mls_context_destroy(context_struct_t * c)
+{
+ if (c == NULL)
+ return;
+
+ mls_range_destroy(&c->range);
+ mls_context_init(c);
+}
+
+static inline void context_init(context_struct_t * c)
+{
+ memset(c, 0, sizeof(*c));
+}
+
+static inline int context_cpy(context_struct_t * dst, context_struct_t * src)
+{
+ dst->user = src->user;
+ dst->role = src->role;
+ dst->type = src->type;
+ return mls_context_cpy(dst, src);
+}
+
+static inline void context_destroy(context_struct_t * c)
+{
+ if (c == NULL)
+ return;
+
+ c->user = c->role = c->type = 0;
+ mls_context_destroy(c);
+}
+
+static inline int context_cmp(context_struct_t * c1, context_struct_t * c2)
+{
+ return ((c1->user == c2->user) &&
+ (c1->role == c2->role) &&
+ (c1->type == c2->type) && mls_context_cmp(c1, c2));
+}
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/ebitmap.h b/libsepol/include/sepol/policydb/ebitmap.h
new file mode 100644
index 0000000..7b3508d
--- /dev/null
+++ b/libsepol/include/sepol/policydb/ebitmap.h
@@ -0,0 +1,98 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * An extensible bitmap is a bitmap that supports an
+ * arbitrary number of bits. Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ */
+
+#ifndef _SEPOL_POLICYDB_EBITMAP_H_
+#define _SEPOL_POLICYDB_EBITMAP_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define MAPTYPE uint64_t /* portion of bitmap in each node */
+#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
+#define MAPBIT 1ULL /* a bit in the node bitmap */
+
+typedef struct ebitmap_node {
+ uint32_t startbit; /* starting position in the total bitmap */
+ MAPTYPE map; /* this node's portion of the bitmap */
+ struct ebitmap_node *next;
+} ebitmap_node_t;
+
+typedef struct ebitmap {
+ ebitmap_node_t *node; /* first node in the bitmap */
+ uint32_t highbit; /* highest position in the total bitmap */
+} ebitmap_t;
+
+#define ebitmap_length(e) ((e)->highbit)
+#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+#define ebitmap_startnode(e) ((e)->node)
+
+static inline unsigned int ebitmap_start(const ebitmap_t * e,
+ ebitmap_node_t ** n)
+{
+
+ *n = e->node;
+ return ebitmap_startbit(e);
+}
+
+static inline void ebitmap_init(ebitmap_t * e)
+{
+ memset(e, 0, sizeof(*e));
+}
+
+static inline unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit)
+{
+ if ((bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next) {
+ *n = (*n)->next;
+ return (*n)->startbit;
+ }
+
+ return (bit + 1);
+}
+
+static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit)
+{
+ if (n->map & (MAPBIT << (bit - n->startbit)))
+ return 1;
+ return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1);
+extern int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2);
+extern int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2);
+extern int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit);
+extern int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit);
+extern unsigned int ebitmap_cardinality(ebitmap_t *e1);
+extern int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2);
+extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src);
+extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2);
+extern int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2);
+extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit);
+extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value);
+extern void ebitmap_destroy(ebitmap_t * e);
+extern int ebitmap_read(ebitmap_t * e, void *fp);
+
+__END_DECLS
+#endif /* _EBITMAP_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/expand.h b/libsepol/include/sepol/policydb/expand.h
new file mode 100644
index 0000000..a8de41e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/expand.h
@@ -0,0 +1,83 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_EXPAND_H
+#define _SEPOL_POLICYDB_EXPAND_H
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/conditional.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * Expand only the avrules for a module. It is valid for this function
+ * to expand base into itself (i.e. base == out); the typemap for
+ * this special case should map type[i] to i+1. Likewise the boolmap
+ * should map bool[i] to i + 1. This function optionally expands
+ * neverallow rules. If neverallow rules are expanded, there is no
+ * need to copy them and doing so could cause duplicate entries when
+ * base == out. If the neverallow rules are not expanded, they are
+ * just copied to the destination policy so that assertion checking
+ * can be performed after expand. No assertion or hierarchy checking
+ * is performed by this function.
+ */
+extern int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+ policydb_t * out, uint32_t * typemap, uint32_t * boolmap,
+ uint32_t * rolemap, uint32_t * usermap,
+ int verbose, int expand_neverallow);
+/*
+ * Expand all parts of a module. Neverallow rules are not expanded (only
+ * copied). It is not valid to expand base into itself. If check is non-zero,
+ * performs hierarchy and assertion checking.
+ */
+extern int expand_module(sepol_handle_t * handle,
+ policydb_t * base, policydb_t * out,
+ int verbose, int check);
+extern int convert_type_ebitmap(ebitmap_t * src, ebitmap_t * dst,
+ uint32_t * typemap);
+extern int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+ type_set_t * set, ebitmap_t * types,
+ unsigned char alwaysexpand);
+extern int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+ unsigned char alwaysexpand);
+extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap);
+extern int mls_semantic_level_expand(mls_semantic_level_t *sl, mls_level_t *l,
+ policydb_t *p, sepol_handle_t *h);
+extern int mls_semantic_range_expand(mls_semantic_range_t *sr, mls_range_t *r,
+ policydb_t *p, sepol_handle_t *h);
+extern int expand_rule(sepol_handle_t * handle,
+ policydb_t * source_pol,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other,
+ int enabled);
+
+extern int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa);
+
+extern int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+ cond_av_list_t ** newl, avtab_t * expa);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/flask.h b/libsepol/include/sepol/policydb/flask.h
new file mode 100644
index 0000000..3134284
--- /dev/null
+++ b/libsepol/include/sepol/policydb/flask.h
@@ -0,0 +1,94 @@
+/* This file is automatically generated. Do not edit. */
+#ifndef _SEPOL_POLICYDB_FLASK_H_
+#define _SEPOL_POLICYDB_FLASK_H_
+
+/*
+ * Security object class definitions
+ */
+#define SECCLASS_SECURITY 1
+#define SECCLASS_PROCESS 2
+#define SECCLASS_SYSTEM 3
+#define SECCLASS_CAPABILITY 4
+#define SECCLASS_FILESYSTEM 5
+#define SECCLASS_FILE 6
+#define SECCLASS_DIR 7
+#define SECCLASS_FD 8
+#define SECCLASS_LNK_FILE 9
+#define SECCLASS_CHR_FILE 10
+#define SECCLASS_BLK_FILE 11
+#define SECCLASS_SOCK_FILE 12
+#define SECCLASS_FIFO_FILE 13
+#define SECCLASS_SOCKET 14
+#define SECCLASS_TCP_SOCKET 15
+#define SECCLASS_UDP_SOCKET 16
+#define SECCLASS_RAWIP_SOCKET 17
+#define SECCLASS_NODE 18
+#define SECCLASS_NETIF 19
+#define SECCLASS_NETLINK_SOCKET 20
+#define SECCLASS_PACKET_SOCKET 21
+#define SECCLASS_KEY_SOCKET 22
+#define SECCLASS_UNIX_STREAM_SOCKET 23
+#define SECCLASS_UNIX_DGRAM_SOCKET 24
+#define SECCLASS_SEM 25
+#define SECCLASS_MSG 26
+#define SECCLASS_MSGQ 27
+#define SECCLASS_SHM 28
+#define SECCLASS_IPC 29
+#define SECCLASS_PASSWD 30
+#define SECCLASS_DRAWABLE 31
+#define SECCLASS_WINDOW 32
+#define SECCLASS_GC 33
+#define SECCLASS_FONT 34
+#define SECCLASS_COLORMAP 35
+#define SECCLASS_PROPERTY 36
+#define SECCLASS_CURSOR 37
+#define SECCLASS_XCLIENT 38
+#define SECCLASS_XINPUT 39
+#define SECCLASS_XSERVER 40
+#define SECCLASS_XEXTENSION 41
+#define SECCLASS_PAX 42
+#define SECCLASS_NETLINK_ROUTE_SOCKET 43
+#define SECCLASS_NETLINK_FIREWALL_SOCKET 44
+#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45
+#define SECCLASS_NETLINK_NFLOG_SOCKET 46
+#define SECCLASS_NETLINK_XFRM_SOCKET 47
+#define SECCLASS_NETLINK_SELINUX_SOCKET 48
+#define SECCLASS_NETLINK_AUDIT_SOCKET 49
+#define SECCLASS_NETLINK_IP6FW_SOCKET 50
+#define SECCLASS_NETLINK_DNRT_SOCKET 51
+#define SECCLASS_DBUS 52
+
+/*
+ * Security identifier indices for initial entities
+ */
+#define SECINITSID_KERNEL 1
+#define SECINITSID_SECURITY 2
+#define SECINITSID_UNLABELED 3
+#define SECINITSID_FS 4
+#define SECINITSID_FILE 5
+#define SECINITSID_FILE_LABELS 6
+#define SECINITSID_INIT 7
+#define SECINITSID_ANY_SOCKET 8
+#define SECINITSID_PORT 9
+#define SECINITSID_NETIF 10
+#define SECINITSID_NETMSG 11
+#define SECINITSID_NODE 12
+#define SECINITSID_IGMP_PACKET 13
+#define SECINITSID_ICMP_SOCKET 14
+#define SECINITSID_TCP_SOCKET 15
+#define SECINITSID_SYSCTL_MODPROBE 16
+#define SECINITSID_SYSCTL 17
+#define SECINITSID_SYSCTL_FS 18
+#define SECINITSID_SYSCTL_KERNEL 19
+#define SECINITSID_SYSCTL_NET 20
+#define SECINITSID_SYSCTL_NET_UNIX 21
+#define SECINITSID_SYSCTL_VM 22
+#define SECINITSID_SYSCTL_DEV 23
+#define SECINITSID_KMOD 24
+#define SECINITSID_POLICY 25
+#define SECINITSID_SCMP_PACKET 26
+#define SECINITSID_DEVNULL 27
+
+#define SECINITSID_NUM 27
+
+#endif
diff --git a/libsepol/include/sepol/policydb/flask_types.h b/libsepol/include/sepol/policydb/flask_types.h
new file mode 100644
index 0000000..2a59565
--- /dev/null
+++ b/libsepol/include/sepol/policydb/flask_types.h
@@ -0,0 +1,65 @@
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+#ifndef _SEPOL_POLICYDB_FLASK_TYPES_H_
+#define _SEPOL_POLICYDB_FLASK_TYPES_H_
+
+/*
+ * The basic Flask types and constants.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy. The security context type
+ * is defined as a variable-length string that can be
+ * interpreted by any application or user with an
+ * understanding of the security policy.
+ */
+typedef char *sepol_security_context_t;
+
+/*
+ * An access vector (AV) is a collection of related permissions
+ * for a pair of SIDs. The bits within an access vector
+ * are interpreted differently depending on the class of
+ * the object. The access vector interpretations are specified
+ * in flask/access_vectors, and the corresponding constants
+ * for permissions are defined in the automatically generated
+ * header file av_permissions.h.
+ */
+typedef uint32_t sepol_access_vector_t;
+
+/*
+ * Each object class is identified by a fixed-size value.
+ * The set of security classes is specified in flask/security_classes,
+ * with the corresponding constants defined in the automatically
+ * generated header file flask.h.
+ */
+typedef uint16_t sepol_security_class_t;
+#define SEPOL_SECCLASS_NULL 0x0000 /* no class */
+
+#define SELINUX_MAGIC 0xf97cff8c
+#define SELINUX_MOD_MAGIC 0xf97cff8d
+
+typedef uint32_t sepol_security_id_t;
+#define SEPOL_SECSID_NULL 0
+
+struct sepol_av_decision {
+ sepol_access_vector_t allowed;
+ sepol_access_vector_t decided;
+ sepol_access_vector_t auditallow;
+ sepol_access_vector_t auditdeny;
+ uint32_t seqno;
+};
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
new file mode 100644
index 0000000..0afc59c
--- /dev/null
+++ b/libsepol/include/sepol/policydb/hashtab.h
@@ -0,0 +1,140 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A hash table (hashtab) maintains associations between
+ * key values and datum values. The type of the key values
+ * and the type of the datum values is arbitrary. The
+ * functions for hash computation and key comparison are
+ * provided by the creator of the table.
+ */
+
+#ifndef _SEPOL_POLICYDB_HASHTAB_H_
+#define _SEPOL_POLICYDB_HASHTAB_H_
+
+#include <sepol/errcodes.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef char *hashtab_key_t; /* generic key type */
+typedef void *hashtab_datum_t; /* generic datum type */
+
+typedef struct hashtab_node *hashtab_ptr_t;
+
+typedef struct hashtab_node {
+ hashtab_key_t key;
+ hashtab_datum_t datum;
+ hashtab_ptr_t next;
+} hashtab_node_t;
+
+typedef struct hashtab_val {
+ hashtab_ptr_t *htable; /* hash table */
+ unsigned int size; /* number of slots in hash table */
+ uint32_t nel; /* number of elements in hash table */
+ unsigned int (*hash_value) (struct hashtab_val * h, hashtab_key_t key); /* hash function */
+ int (*keycmp) (struct hashtab_val * h, hashtab_key_t key1, hashtab_key_t key2); /* key comparison function */
+} hashtab_val_t;
+
+typedef hashtab_val_t *hashtab_t;
+
+/*
+ Creates a new hash table with the specified characteristics.
+
+ Returns NULL if insufficent space is available or
+ the new hash table otherwise.
+ */
+extern hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+ const hashtab_key_t
+ key),
+ int (*keycmp) (hashtab_t h,
+ const hashtab_key_t key1,
+ const hashtab_key_t key2),
+ unsigned int size);
+/*
+ Inserts the specified (key, datum) pair into the specified hash table.
+
+ Returns SEPOL_ENOMEM if insufficient space is available or
+ SEPOL_EEXIST if there is already an entry with the same key or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_insert(hashtab_t h, hashtab_key_t k, hashtab_datum_t d);
+
+/*
+ Removes the entry with the specified key from the hash table.
+ Applies the specified destroy function to (key,datum,args) for
+ the entry.
+
+ Returns SEPOL_ENOENT if no entry has the specified key or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_remove(hashtab_t h, hashtab_key_t k,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Insert or replace the specified (key, datum) pair in the specified
+ hash table. If an entry for the specified key already exists,
+ then the specified destroy function is applied to (key,datum,args)
+ for the entry prior to replacing the entry's contents.
+
+ Returns SEPOL_ENOMEM if insufficient space is available or
+ SEPOL_OK otherwise.
+ */
+extern int hashtab_replace(hashtab_t h, hashtab_key_t k, hashtab_datum_t d,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Searches for the entry with the specified key in the hash table.
+
+ Returns NULL if no entry has the specified key or
+ the datum of the entry otherwise.
+ */
+extern hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t k);
+
+/*
+ Destroys the specified hash table.
+ */
+extern void hashtab_destroy(hashtab_t h);
+
+/*
+ Applies the specified apply function to (key,datum,args)
+ for each entry in the specified hash table.
+
+ The order in which the function is applied to the entries
+ is dependent upon the internal structure of the hash table.
+
+ If apply returns a non-zero status, then hashtab_map will cease
+ iterating through the hash table and will propagate the error
+ return to its caller.
+ */
+extern int hashtab_map(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args);
+
+/*
+ Same as hashtab_map, except that if apply returns a non-zero status,
+ then the (key,datum) pair will be removed from the hashtab and the
+ destroy function will be applied to (key,datum,args).
+ */
+extern void hashtab_map_remove_on_error(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void *args);
+
+extern void hashtab_hash_eval(hashtab_t h, char *tag);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/hierarchy.h b/libsepol/include/sepol/policydb/hierarchy.h
new file mode 100644
index 0000000..88bc02e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/hierarchy.h
@@ -0,0 +1,47 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal items.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_HIERARCHY_H_
+#define _SEPOL_POLICYDB_HIERARCHY_H_
+
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p);
+
+extern void bounds_destroy_bad(avtab_ptr_t cur);
+extern int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+ uint32_t parent, avtab_ptr_t *bad, int *numbad);
+
+extern int bounds_check_users(sepol_handle_t *handle, policydb_t *p);
+extern int bounds_check_roles(sepol_handle_t *handle, policydb_t *p);
+extern int bounds_check_types(sepol_handle_t *handle, policydb_t *p);
+
+extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/link.h b/libsepol/include/sepol/policydb/link.h
new file mode 100644
index 0000000..7c7c9be
--- /dev/null
+++ b/libsepol/include/sepol/policydb/link.h
@@ -0,0 +1,24 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@mentalrootkit.com>
+ */
+
+#ifndef _SEPOL_POLICYDB_LINK_H
+#define _SEPOL_POLICYDB_LINK_H
+
+#include <sepol/handle.h>
+#include <sepol/errcodes.h>
+#include <sepol/policydb/policydb.h>
+
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int link_modules(sepol_handle_t * handle,
+ policydb_t * b, policydb_t ** mods, int len,
+ int verbose);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/mls_types.h b/libsepol/include/sepol/policydb/mls_types.h
new file mode 100644
index 0000000..4bf7367
--- /dev/null
+++ b/libsepol/include/sepol/policydb/mls_types.h
@@ -0,0 +1,156 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_MLS_TYPES_H_
+#define _SEPOL_POLICYDB_MLS_TYPES_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/flask_types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct mls_level {
+ uint32_t sens; /* sensitivity */
+ ebitmap_t cat; /* category set */
+} mls_level_t;
+
+typedef struct mls_range {
+ mls_level_t level[2]; /* low == level[0], high == level[1] */
+} mls_range_t;
+
+static inline int mls_level_cpy(struct mls_level *dst, struct mls_level *src)
+{
+
+ dst->sens = src->sens;
+ if (ebitmap_cpy(&dst->cat, &src->cat) < 0)
+ return -1;
+ return 0;
+}
+
+static inline void mls_level_init(struct mls_level *level)
+{
+
+ memset(level, 0, sizeof(mls_level_t));
+}
+
+static inline void mls_level_destroy(struct mls_level *level)
+{
+
+ if (level == NULL)
+ return;
+
+ ebitmap_destroy(&level->cat);
+ mls_level_init(level);
+}
+
+static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2)
+{
+ return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2)
+{
+ return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
+
+static inline int mls_range_cpy(mls_range_t * dst, mls_range_t * src)
+{
+
+ if (mls_level_cpy(&dst->level[0], &src->level[0]) < 0)
+ goto err;
+
+ if (mls_level_cpy(&dst->level[1], &src->level[1]) < 0)
+ goto err_destroy;
+
+ return 0;
+
+ err_destroy:
+ mls_level_destroy(&dst->level[0]);
+
+ err:
+ return -1;
+}
+
+static inline void mls_range_init(struct mls_range *r)
+{
+ mls_level_init(&r->level[0]);
+ mls_level_init(&r->level[1]);
+}
+
+static inline void mls_range_destroy(struct mls_range *r)
+{
+ mls_level_destroy(&r->level[0]);
+ mls_level_destroy(&r->level[1]);
+}
+
+static inline int mls_range_eq(struct mls_range *r1, struct mls_range *r2)
+{
+ return (mls_level_eq(&r1->level[0], &r2->level[0]) &&
+ mls_level_eq(&r1->level[1], &r2->level[1]));
+}
+
+typedef struct mls_semantic_cat {
+ uint32_t low; /* first bit this struct represents */
+ uint32_t high; /* last bit represented - equals low for a single cat */
+ struct mls_semantic_cat *next;
+} mls_semantic_cat_t;
+
+typedef struct mls_semantic_level {
+ uint32_t sens;
+ mls_semantic_cat_t *cat;
+} mls_semantic_level_t;
+
+typedef struct mls_semantic_range {
+ mls_semantic_level_t level[2];
+} mls_semantic_range_t;
+
+extern void mls_semantic_cat_init(mls_semantic_cat_t *c);
+extern void mls_semantic_cat_destroy(mls_semantic_cat_t *c);
+extern void mls_semantic_level_init(mls_semantic_level_t *l);
+extern void mls_semantic_level_destroy(mls_semantic_level_t *l);
+extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, mls_semantic_level_t *src);
+extern void mls_semantic_range_init(mls_semantic_range_t *r);
+extern void mls_semantic_range_destroy(mls_semantic_range_t *r);
+extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, mls_semantic_range_t *src);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/module.h b/libsepol/include/sepol/policydb/module.h
new file mode 100644
index 0000000..3fe560c
--- /dev/null
+++ b/libsepol/include/sepol/policydb/module.h
@@ -0,0 +1,52 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_POLICYDB_MODULE_H_
+#define _SEPOL_POLICYDB_MODULE_H_
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <sepol/module.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sys/cdefs.h>
+
+#define SEPOL_MODULE_PACKAGE_MAGIC 0xf97cff8f
+
+__BEGIN_DECLS
+
+struct sepol_module_package {
+ sepol_policydb_t *policy;
+ uint32_t version;
+ char *file_contexts;
+ size_t file_contexts_len;
+ char *seusers;
+ size_t seusers_len;
+ char *user_extra;
+ size_t user_extra_len;
+ char *netfilter_contexts;
+ size_t netfilter_contexts_len;
+};
+
+extern int sepol_module_package_init(sepol_module_package_t * p);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/polcaps.h b/libsepol/include/sepol/policydb/polcaps.h
new file mode 100644
index 0000000..74b7c9e
--- /dev/null
+++ b/libsepol/include/sepol/policydb/polcaps.h
@@ -0,0 +1,25 @@
+#ifndef _SEPOL_POLICYDB_POLCAPS_H_
+#define _SEPOL_POLICYDB_POLCAPS_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Policy capabilities */
+enum {
+ POLICYDB_CAPABILITY_NETPEER,
+ POLICYDB_CAPABILITY_OPENPERM,
+ POLICYDB_CAPABILITY_REDHAT1, /* reserved for RH testing of ptrace_child */
+ POLICYDB_CAPABILITY_ALWAYSNETWORK,
+ __POLICYDB_CAPABILITY_MAX
+};
+#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+
+/* Convert a capability name to number. */
+extern int sepol_polcap_getnum(const char *name);
+
+/* Convert a capability number to name. */
+extern const char *sepol_polcap_getname(int capnum);
+
+__END_DECLS
+#endif /* _SEPOL_POLICYDB_POLCAPS_H_ */
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
new file mode 100644
index 0000000..26cec13
--- /dev/null
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -0,0 +1,774 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Module support
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * A policy database (policydb) specifies the
+ * configuration data for the security policy.
+ */
+
+#ifndef _SEPOL_POLICYDB_POLICYDB_H_
+#define _SEPOL_POLICYDB_POLICYDB_H_
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include <sepol/policydb.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/symtab.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/sidtab.h>
+#include <sys/cdefs.h>
+
+#define ERRMSG_LEN 1024
+
+#define POLICYDB_SUCCESS 0
+#define POLICYDB_ERROR -1
+#define POLICYDB_UNSUPPORTED -2
+
+__BEGIN_DECLS
+
+/*
+ * A datum type is defined for each kind of symbol
+ * in the configuration data: individual permissions,
+ * common prefixes for access vectors, classes,
+ * users, roles, types, sensitivities, categories, etc.
+ */
+
+/* type set preserves data needed by modules such as *, ~ and attributes */
+typedef struct type_set {
+ ebitmap_t types;
+ ebitmap_t negset;
+#define TYPE_STAR 1
+#define TYPE_COMP 2
+ uint32_t flags;
+} type_set_t;
+
+typedef struct role_set {
+ ebitmap_t roles;
+#define ROLE_STAR 1
+#define ROLE_COMP 2
+ uint32_t flags;
+} role_set_t;
+
+/* Permission attributes */
+typedef struct perm_datum {
+ symtab_datum_t s;
+} perm_datum_t;
+
+/* Attributes of a common prefix for access vectors */
+typedef struct common_datum {
+ symtab_datum_t s;
+ symtab_t permissions; /* common permissions */
+} common_datum_t;
+
+/* Class attributes */
+typedef struct class_datum {
+ symtab_datum_t s;
+ char *comkey; /* common name */
+ common_datum_t *comdatum; /* common datum */
+ symtab_t permissions; /* class-specific permission symbol table */
+ constraint_node_t *constraints; /* constraints on class permissions */
+ constraint_node_t *validatetrans; /* special transition rules */
+/* Options how a new object user and role should be decided */
+#define DEFAULT_SOURCE 1
+#define DEFAULT_TARGET 2
+ char default_user;
+ char default_role;
+ char default_type;
+/* Options how a new object range should be decided */
+#define DEFAULT_SOURCE_LOW 1
+#define DEFAULT_SOURCE_HIGH 2
+#define DEFAULT_SOURCE_LOW_HIGH 3
+#define DEFAULT_TARGET_LOW 4
+#define DEFAULT_TARGET_HIGH 5
+#define DEFAULT_TARGET_LOW_HIGH 6
+ char default_range;
+} class_datum_t;
+
+/* Role attributes */
+typedef struct role_datum {
+ symtab_datum_t s;
+ ebitmap_t dominates; /* set of roles dominated by this role */
+ type_set_t types; /* set of authorized types for role */
+ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */
+ uint32_t bounds; /* bounds role, if exist */
+#define ROLE_ROLE 0 /* regular role in kernel policies */
+#define ROLE_ATTRIB 1 /* attribute */
+ uint32_t flavor;
+ ebitmap_t roles; /* roles with this attribute */
+} role_datum_t;
+
+typedef struct role_trans {
+ uint32_t role; /* current role */
+ uint32_t type; /* program executable type, or new object type */
+ uint32_t tclass; /* process class, or new object class */
+ uint32_t new_role; /* new role */
+ struct role_trans *next;
+} role_trans_t;
+
+typedef struct role_allow {
+ uint32_t role; /* current role */
+ uint32_t new_role; /* new role */
+ struct role_allow *next;
+} role_allow_t;
+
+/* filename_trans rules */
+typedef struct filename_trans {
+ uint32_t stype;
+ uint32_t ttype;
+ uint32_t tclass;
+ char *name;
+ uint32_t otype;
+ struct filename_trans *next;
+} filename_trans_t;
+
+/* Type attributes */
+typedef struct type_datum {
+ symtab_datum_t s;
+ uint32_t primary; /* primary name? can be set to primary value if below is TYPE_ */
+#define TYPE_TYPE 0 /* regular type or alias in kernel policies */
+#define TYPE_ATTRIB 1 /* attribute */
+#define TYPE_ALIAS 2 /* alias in modular policy */
+ uint32_t flavor;
+ ebitmap_t types; /* types with this attribute */
+#define TYPE_FLAGS_PERMISSIVE 0x01
+ uint32_t flags;
+ uint32_t bounds; /* bounds type, if exist */
+} type_datum_t;
+
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY 0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002
+#define TYPEDATUM_PROPERTY_ALIAS 0x0004 /* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE 0x0008 /* userspace only */
+
+/* User attributes */
+typedef struct user_datum {
+ symtab_datum_t s;
+ role_set_t roles; /* set of authorized roles for user */
+ mls_semantic_range_t range; /* MLS range (min. - max.) for user */
+ mls_semantic_level_t dfltlevel; /* default login MLS level for user */
+ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */
+ mls_range_t exp_range; /* expanded range used for validation */
+ mls_level_t exp_dfltlevel; /* expanded range used for validation */
+ uint32_t bounds; /* bounds user, if exist */
+} user_datum_t;
+
+/* Sensitivity attributes */
+typedef struct level_datum {
+ mls_level_t *level; /* sensitivity and associated categories */
+ unsigned char isalias; /* is this sensitivity an alias for another? */
+ unsigned char defined;
+} level_datum_t;
+
+/* Category attributes */
+typedef struct cat_datum {
+ symtab_datum_t s;
+ unsigned char isalias; /* is this category an alias for another? */
+} cat_datum_t;
+
+typedef struct range_trans {
+ uint32_t source_type;
+ uint32_t target_type;
+ uint32_t target_class;
+ mls_range_t target_range;
+ struct range_trans *next;
+} range_trans_t;
+
+/* Boolean data type */
+typedef struct cond_bool_datum {
+ symtab_datum_t s;
+ int state;
+#define COND_BOOL_FLAGS_TUNABLE 0x01 /* is this a tunable? */
+ uint32_t flags;
+} cond_bool_datum_t;
+
+struct cond_node;
+
+typedef struct cond_node cond_list_t;
+struct cond_av_list;
+
+typedef struct class_perm_node {
+ uint32_t tclass;
+ uint32_t data; /* permissions or new type */
+ struct class_perm_node *next;
+} class_perm_node_t;
+
+#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
+#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
+#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
+#define EXTENDED_PERMS_LEN 8
+
+typedef struct av_extended_perms {
+#define AVRULE_XPERMS_IOCTLFUNCTION 0x01
+#define AVRULE_XPERMS_IOCTLDRIVER 0x02
+ uint8_t specified;
+ uint8_t driver;
+ /* 256 bits of permissions */
+ uint32_t perms[EXTENDED_PERMS_LEN];
+} av_extended_perms_t;
+
+typedef struct avrule {
+/* these typedefs are almost exactly the same as those in avtab.h - they are
+ * here because of the need to include neverallow and dontaudit messages */
+#define AVRULE_ALLOWED 0x0001
+#define AVRULE_AUDITALLOW 0x0002
+#define AVRULE_AUDITDENY 0x0004
+#define AVRULE_DONTAUDIT 0x0008
+#define AVRULE_NEVERALLOW 0x0080
+#define AVRULE_AV (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW)
+#define AVRULE_TRANSITION 0x0010
+#define AVRULE_MEMBER 0x0020
+#define AVRULE_CHANGE 0x0040
+#define AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
+#define AVRULE_XPERMS_ALLOWED 0x0100
+#define AVRULE_XPERMS_AUDITALLOW 0x0200
+#define AVRULE_XPERMS_DONTAUDIT 0x0400
+#define AVRULE_XPERMS_NEVERALLOW 0x0800
+#define AVRULE_XPERMS (AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
+ AVRULE_XPERMS_DONTAUDIT | AVRULE_XPERMS_NEVERALLOW)
+ uint32_t specified;
+#define RULE_SELF 1
+ uint32_t flags;
+ type_set_t stypes;
+ type_set_t ttypes;
+ class_perm_node_t *perms;
+ av_extended_perms_t *xperms;
+ unsigned long line; /* line number from policy.conf where
+ * this rule originated */
+ /* source file name and line number (e.g. .te file) */
+ char *source_filename;
+ unsigned long source_line;
+ struct avrule *next;
+} avrule_t;
+
+typedef struct role_trans_rule {
+ role_set_t roles; /* current role */
+ type_set_t types; /* program executable type, or new object type */
+ ebitmap_t classes; /* process class, or new object class */
+ uint32_t new_role; /* new role */
+ struct role_trans_rule *next;
+} role_trans_rule_t;
+
+typedef struct role_allow_rule {
+ role_set_t roles; /* current role */
+ role_set_t new_roles; /* new roles */
+ struct role_allow_rule *next;
+} role_allow_rule_t;
+
+typedef struct filename_trans_rule {
+ type_set_t stypes;
+ type_set_t ttypes;
+ uint32_t tclass;
+ char *name;
+ uint32_t otype; /* new type */
+ struct filename_trans_rule *next;
+} filename_trans_rule_t;
+
+typedef struct range_trans_rule {
+ type_set_t stypes;
+ type_set_t ttypes;
+ ebitmap_t tclasses;
+ mls_semantic_range_t trange;
+ struct range_trans_rule *next;
+} range_trans_rule_t;
+
+/*
+ * The configuration data includes security contexts for
+ * initial SIDs, unlabeled file systems, TCP and UDP port numbers,
+ * network interfaces, and nodes. This structure stores the
+ * relevant data for one such entry. Entries of the same kind
+ * (e.g. all initial SIDs) are linked together into a list.
+ */
+typedef struct ocontext {
+ union {
+ char *name; /* name of initial SID, fs, netif, fstype, path */
+ struct {
+ uint8_t protocol;
+ uint16_t low_port;
+ uint16_t high_port;
+ } port; /* TCP or UDP port information */
+ struct {
+ uint32_t addr; /* network order */
+ uint32_t mask; /* network order */
+ } node; /* node information */
+ struct {
+ uint32_t addr[4]; /* network order */
+ uint32_t mask[4]; /* network order */
+ } node6; /* IPv6 node information */
+ uint32_t device;
+ uint16_t pirq;
+ struct {
+ uint64_t low_iomem;
+ uint64_t high_iomem;
+ } iomem;
+ struct {
+ uint32_t low_ioport;
+ uint32_t high_ioport;
+ } ioport;
+ } u;
+ union {
+ uint32_t sclass; /* security class for genfs */
+ uint32_t behavior; /* labeling behavior for fs_use */
+ } v;
+ context_struct_t context[2]; /* security context(s) */
+ sepol_security_id_t sid[2]; /* SID(s) */
+ struct ocontext *next;
+} ocontext_t;
+
+typedef struct genfs {
+ char *fstype;
+ struct ocontext *head;
+ struct genfs *next;
+} genfs_t;
+
+/* symbol table array indices */
+#define SYM_COMMONS 0
+#define SYM_CLASSES 1
+#define SYM_ROLES 2
+#define SYM_TYPES 3
+#define SYM_USERS 4
+#define SYM_BOOLS 5
+#define SYM_LEVELS 6
+#define SYM_CATS 7
+#define SYM_NUM 8
+
+/* object context array indices */
+#define OCON_ISID 0 /* initial SIDs */
+#define OCON_FS 1 /* unlabeled file systems */
+#define OCON_PORT 2 /* TCP and UDP port numbers */
+#define OCON_NETIF 3 /* network interfaces */
+#define OCON_NODE 4 /* nodes */
+#define OCON_FSUSE 5 /* fs_use */
+#define OCON_NODE6 6 /* IPv6 nodes */
+#define OCON_GENFS 7 /* needed for ocontext_supported */
+
+/* object context array indices for Xen */
+#define OCON_XEN_ISID 0 /* initial SIDs */
+#define OCON_XEN_PIRQ 1 /* physical irqs */
+#define OCON_XEN_IOPORT 2 /* io ports */
+#define OCON_XEN_IOMEM 3 /* io memory */
+#define OCON_XEN_PCIDEVICE 4 /* pci devices */
+#define OCON_XEN_DEVICETREE 5 /* device tree node */
+
+/* OCON_NUM needs to be the largest index in any platform's ocontext array */
+#define OCON_NUM 7
+
+/* section: module information */
+
+/* scope_index_t holds all of the symbols that are in scope in a
+ * particular situation. The bitmaps are indices (and thus must
+ * subtract one) into the global policydb->scope array. */
+typedef struct scope_index {
+ ebitmap_t scope[SYM_NUM];
+#define p_classes_scope scope[SYM_CLASSES]
+#define p_roles_scope scope[SYM_ROLES]
+#define p_types_scope scope[SYM_TYPES]
+#define p_users_scope scope[SYM_USERS]
+#define p_bools_scope scope[SYM_BOOLS]
+#define p_sens_scope scope[SYM_LEVELS]
+#define p_cat_scope scope[SYM_CATS]
+
+ /* this array maps from class->value to the permissions within
+ * scope. if bit (perm->value - 1) is set in map
+ * class_perms_map[class->value - 1] then that permission is
+ * enabled for this class within this decl. */
+ ebitmap_t *class_perms_map;
+ /* total number of classes in class_perms_map array */
+ uint32_t class_perms_len;
+} scope_index_t;
+
+/* a list of declarations for a particular avrule_decl */
+
+/* These two structs declare a block of policy that has TE and RBAC
+ * statements and declarations. The root block (the global policy)
+ * can never have an ELSE branch. */
+typedef struct avrule_decl {
+ uint32_t decl_id;
+ uint32_t enabled; /* whether this block is enabled */
+
+ cond_list_t *cond_list;
+ avrule_t *avrules;
+ role_trans_rule_t *role_tr_rules;
+ role_allow_rule_t *role_allow_rules;
+ range_trans_rule_t *range_tr_rules;
+ scope_index_t required; /* symbols needed to activate this block */
+ scope_index_t declared; /* symbols declared within this block */
+
+ /* type transition rules with a 'name' component */
+ filename_trans_rule_t *filename_trans_rules;
+
+ /* for additive statements (type attribute, roles, and users) */
+ symtab_t symtab[SYM_NUM];
+
+ /* In a linked module this will contain the name of the module
+ * from which this avrule_decl originated. */
+ char *module_name;
+
+ struct avrule_decl *next;
+} avrule_decl_t;
+
+typedef struct avrule_block {
+ avrule_decl_t *branch_list;
+ avrule_decl_t *enabled; /* pointer to which branch is enabled. this is
+ used in linking and never written to disk */
+#define AVRULE_OPTIONAL 1
+ uint32_t flags; /* any flags for this block, currently just optional */
+ struct avrule_block *next;
+} avrule_block_t;
+
+/* Every identifier has its own scope datum. The datum describes if
+ * the item is to be included into the final policy during
+ * expansion. */
+typedef struct scope_datum {
+/* Required for this decl */
+#define SCOPE_REQ 1
+/* Declared in this decl */
+#define SCOPE_DECL 2
+ uint32_t scope;
+ uint32_t *decl_ids;
+ uint32_t decl_ids_len;
+ /* decl_ids is a list of avrule_decl's that declare/require
+ * this symbol. If scope==SCOPE_DECL then this is a list of
+ * declarations. If the symbol may only be declared once
+ * (types, bools) then decl_ids_len will be exactly 1. For
+ * implicitly declared things (roles, users) then decl_ids_len
+ * will be at least 1. */
+} scope_datum_t;
+
+/* The policy database */
+typedef struct policydb {
+#define POLICY_KERN SEPOL_POLICY_KERN
+#define POLICY_BASE SEPOL_POLICY_BASE
+#define POLICY_MOD SEPOL_POLICY_MOD
+ uint32_t policy_type;
+ char *name;
+ char *version;
+ int target_platform;
+
+ /* Set when the policydb is modified such that writing is unsupported */
+ int unsupported_format;
+
+ /* Whether this policydb is mls, should always be set */
+ int mls;
+
+ /* symbol tables */
+ symtab_t symtab[SYM_NUM];
+#define p_commons symtab[SYM_COMMONS]
+#define p_classes symtab[SYM_CLASSES]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
+
+ /* symbol names indexed by (value - 1) */
+ char **sym_val_to_name[SYM_NUM];
+#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
+#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
+#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
+#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
+#define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
+#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
+#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+
+ /* class, role, and user attributes indexed by (value - 1) */
+ class_datum_t **class_val_to_struct;
+ role_datum_t **role_val_to_struct;
+ user_datum_t **user_val_to_struct;
+ type_datum_t **type_val_to_struct;
+
+ /* module stuff section -- used in parsing and for modules */
+
+ /* keep track of the scope for every identifier. these are
+ * hash tables, where the key is the identifier name and value
+ * a scope_datum_t. as a convenience, one may use the
+ * p_*_macros (cf. struct scope_index_t declaration). */
+ symtab_t scope[SYM_NUM];
+
+ /* module rule storage */
+ avrule_block_t *global;
+ /* avrule_decl index used for link/expand */
+ avrule_decl_t **decl_val_to_struct;
+
+ /* compiled storage of rules - use for the kernel policy */
+
+ /* type enforcement access vectors and transitions */
+ avtab_t te_avtab;
+
+ /* bools indexed by (value - 1) */
+ cond_bool_datum_t **bool_val_to_struct;
+ /* type enforcement conditional access vectors and transitions */
+ avtab_t te_cond_avtab;
+ /* linked list indexing te_cond_avtab by conditional */
+ cond_list_t *cond_list;
+
+ /* role transitions */
+ role_trans_t *role_tr;
+
+ /* type transition rules with a 'name' component */
+ filename_trans_t *filename_trans;
+
+ /* role allows */
+ role_allow_t *role_allow;
+
+ /* security contexts of initial SIDs, unlabeled file systems,
+ TCP or UDP port numbers, network interfaces and nodes */
+ ocontext_t *ocontexts[OCON_NUM];
+
+ /* security contexts for files in filesystems that cannot support
+ a persistent label mapping or use another
+ fixed labeling behavior. */
+ genfs_t *genfs;
+
+ /* range transitions */
+ range_trans_t *range_tr;
+
+ ebitmap_t *type_attr_map;
+
+ ebitmap_t *attr_type_map; /* not saved in the binary policy */
+
+ ebitmap_t policycaps;
+
+ /* this bitmap is referenced by type NOT the typical type-1 used in other
+ bitmaps. Someday the 0 bit may be used for global permissive */
+ ebitmap_t permissive_map;
+
+ unsigned policyvers;
+
+ unsigned handle_unknown;
+} policydb_t;
+
+struct sepol_policydb {
+ struct policydb p;
+};
+
+extern int policydb_init(policydb_t * p);
+
+extern int policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, policydb_t * policydb);
+
+extern int policydb_to_image(sepol_handle_t * handle,
+ policydb_t * policydb, void **newdata,
+ size_t * newlen);
+
+extern int policydb_index_classes(policydb_t * p);
+
+extern int policydb_index_bools(policydb_t * p);
+
+extern int policydb_index_others(sepol_handle_t * handle, policydb_t * p,
+ unsigned int verbose);
+
+extern int policydb_reindex_users(policydb_t * p);
+
+extern void policydb_destroy(policydb_t * p);
+
+extern int policydb_load_isids(policydb_t * p, sidtab_t * s);
+
+/* Deprecated */
+extern int policydb_context_isvalid(const policydb_t * p,
+ const context_struct_t * c);
+
+extern void symtabs_destroy(symtab_t * symtab);
+extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
+typedef void (*hashtab_destroy_func_t) (hashtab_key_t k, hashtab_datum_t d,
+ void *args);
+extern hashtab_destroy_func_t get_symtab_destroy_func(int sym_num);
+
+extern void class_perm_node_init(class_perm_node_t * x);
+extern void type_set_init(type_set_t * x);
+extern void type_set_destroy(type_set_t * x);
+extern int type_set_cpy(type_set_t * dst, type_set_t * src);
+extern int type_set_or_eq(type_set_t * dst, type_set_t * other);
+extern void role_set_init(role_set_t * x);
+extern void role_set_destroy(role_set_t * x);
+extern void avrule_init(avrule_t * x);
+extern void avrule_destroy(avrule_t * x);
+extern void avrule_list_destroy(avrule_t * x);
+extern void role_trans_rule_init(role_trans_rule_t * x);
+extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
+extern void filename_trans_rule_init(filename_trans_rule_t * x);
+extern void filename_trans_rule_list_destroy(filename_trans_rule_t * x);
+
+extern void role_datum_init(role_datum_t * x);
+extern void role_datum_destroy(role_datum_t * x);
+extern void role_allow_rule_init(role_allow_rule_t * x);
+extern void role_allow_rule_destroy(role_allow_rule_t * x);
+extern void role_allow_rule_list_destroy(role_allow_rule_t * x);
+extern void range_trans_rule_init(range_trans_rule_t *x);
+extern void range_trans_rule_destroy(range_trans_rule_t *x);
+extern void range_trans_rule_list_destroy(range_trans_rule_t *x);
+extern void type_datum_init(type_datum_t * x);
+extern void type_datum_destroy(type_datum_t * x);
+extern void user_datum_init(user_datum_t * x);
+extern void user_datum_destroy(user_datum_t * x);
+extern void level_datum_init(level_datum_t * x);
+extern void level_datum_destroy(level_datum_t * x);
+extern void cat_datum_init(cat_datum_t * x);
+extern void cat_datum_destroy(cat_datum_t * x);
+extern int check_assertion(policydb_t *p, avrule_t *avrule);
+extern int check_assertions(sepol_handle_t * handle,
+ policydb_t * p, avrule_t * avrules);
+
+extern int symtab_insert(policydb_t * x, uint32_t sym,
+ hashtab_key_t key, hashtab_datum_t datum,
+ uint32_t scope, uint32_t avrule_decl_id,
+ uint32_t * value);
+
+/* A policy "file" may be a memory region referenced by a (data, len) pair
+ or a file referenced by a FILE pointer. */
+typedef struct policy_file {
+#define PF_USE_MEMORY 0
+#define PF_USE_STDIO 1
+#define PF_LEN 2 /* total up length in len field */
+ unsigned type;
+ char *data;
+ size_t len;
+ size_t size;
+ FILE *fp;
+ struct sepol_handle *handle;
+} policy_file_t;
+
+struct sepol_policy_file {
+ struct policy_file pf;
+};
+
+extern void policy_file_init(policy_file_t * x);
+
+extern int policydb_read(policydb_t * p, struct policy_file *fp,
+ unsigned int verbose);
+extern int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+ struct policy_file *fp);
+
+extern int policydb_write(struct policydb *p, struct policy_file *pf);
+extern int policydb_set_target_platform(policydb_t *p, int platform);
+
+#define PERM_SYMTAB_SIZE 32
+
+/* Identify specific policy version changes */
+#define POLICYDB_VERSION_BASE 15
+#define POLICYDB_VERSION_BOOL 16
+#define POLICYDB_VERSION_IPV6 17
+#define POLICYDB_VERSION_NLCLASS 18
+#define POLICYDB_VERSION_VALIDATETRANS 19
+#define POLICYDB_VERSION_MLS 19
+#define POLICYDB_VERSION_AVTAB 20
+#define POLICYDB_VERSION_RANGETRANS 21
+#define POLICYDB_VERSION_POLCAP 22
+#define POLICYDB_VERSION_PERMISSIVE 23
+#define POLICYDB_VERSION_BOUNDARY 24
+#define POLICYDB_VERSION_FILENAME_TRANS 25
+#define POLICYDB_VERSION_ROLETRANS 26
+#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
+#define POLICYDB_VERSION_DEFAULT_TYPE 28
+#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
+#define POLICYDB_VERSION_XEN_DEVICETREE 30 /* Xen-specific */
+#define POLICYDB_VERSION_XPERMS_IOCTL 30 /* Linux-specific */
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL
+
+/* Module versions and specific changes*/
+#define MOD_POLICYDB_VERSION_BASE 4
+#define MOD_POLICYDB_VERSION_VALIDATETRANS 5
+#define MOD_POLICYDB_VERSION_MLS 5
+#define MOD_POLICYDB_VERSION_RANGETRANS 6
+#define MOD_POLICYDB_VERSION_MLS_USERS 6
+#define MOD_POLICYDB_VERSION_POLCAP 7
+#define MOD_POLICYDB_VERSION_PERMISSIVE 8
+#define MOD_POLICYDB_VERSION_BOUNDARY 9
+#define MOD_POLICYDB_VERSION_BOUNDARY_ALIAS 10
+#define MOD_POLICYDB_VERSION_FILENAME_TRANS 11
+#define MOD_POLICYDB_VERSION_ROLETRANS 12
+#define MOD_POLICYDB_VERSION_ROLEATTRIB 13
+#define MOD_POLICYDB_VERSION_TUNABLE_SEP 14
+#define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 15
+#define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16
+#define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES 17
+
+#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES
+
+#define POLICYDB_CONFIG_MLS 1
+
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p) \
+ (((p)->policy_type == POLICY_KERN \
+ && p->policyvers >= POLICYDB_VERSION_BOUNDARY) || \
+ ((p)->policy_type != POLICY_KERN \
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
+/* the config flags related to unknown classes/perms are bits 2 and 3 */
+#define DENY_UNKNOWN SEPOL_DENY_UNKNOWN
+#define REJECT_UNKNOWN SEPOL_REJECT_UNKNOWN
+#define ALLOW_UNKNOWN SEPOL_ALLOW_UNKNOWN
+
+#define POLICYDB_CONFIG_UNKNOWN_MASK (DENY_UNKNOWN | REJECT_UNKNOWN | ALLOW_UNKNOWN)
+
+#define OBJECT_R "object_r"
+#define OBJECT_R_VAL 1
+
+#define POLICYDB_MAGIC SELINUX_MAGIC
+#define POLICYDB_STRING "SE Linux"
+#define POLICYDB_XEN_STRING "XenFlask"
+#define POLICYDB_STRING_MAX_LENGTH 32
+#define POLICYDB_MOD_MAGIC SELINUX_MOD_MAGIC
+#define POLICYDB_MOD_STRING "SE Linux Module"
+
+__END_DECLS
+#endif /* _POLICYDB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h
new file mode 100644
index 0000000..8a5dc9a
--- /dev/null
+++ b/libsepol/include/sepol/policydb/services.h
@@ -0,0 +1,234 @@
+
+/* -*- linux-c -*- */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+#ifndef _SEPOL_POLICYDB_SERVICES_H_
+#define _SEPOL_POLICYDB_SERVICES_H_
+
+/*
+ * Security server interface.
+ */
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Set the policydb and sidtab structures to be used by
+ the service functions. If not set, then these default
+ to private structures within libsepol that can only be
+ initialized and accessed via the service functions themselves.
+ Setting the structures explicitly allows a program to directly
+ manipulate them, e.g. checkpolicy populates the structures directly
+ from a source policy rather than from a binary policy. */
+extern int sepol_set_policydb(policydb_t * p);
+extern int sepol_set_sidtab(sidtab_t * s);
+
+/* Modify a policydb for boolean settings. */
+int sepol_genbools_policydb(policydb_t * policydb, const char *booleans);
+
+/* Modify a policydb for user settings. */
+int sepol_genusers_policydb(policydb_t * policydb, const char *usersdir);
+
+/* Load the security policy. This initializes the policydb
+ and sidtab based on the provided binary policy. */
+extern int sepol_load_policy(void *data, size_t len);
+
+/*
+ * Compute access vectors based on a SID pair for
+ * the permissions in a particular class.
+ */
+extern int sepol_compute_av(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_access_vector_t requested, /* IN */
+ struct sepol_av_decision *avd); /* OUT */
+
+/* Same as above, but also return the reason(s) for any
+ denials of the requested permissions. */
+#define SEPOL_COMPUTEAV_TE 1
+#define SEPOL_COMPUTEAV_CONS 2
+#define SEPOL_COMPUTEAV_RBAC 4
+extern int sepol_compute_av_reason(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason);
+
+/*
+ * Same as above, but also returns the constraint expression calculations
+ * whether allowed or denied in a buffer. This buffer is allocated by
+ * this call and must be free'd by the caller using free(3). The contraint
+ * buffer will contain any constraints in infix notation.
+ * If the SHOW_GRANTED flag is set it will show granted and denied
+ * constraints. The default is to show only denied constraints.
+ */
+#define SHOW_GRANTED 1
+extern int sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason,
+ char **reason_buf,
+ unsigned int flags);
+
+/*
+ * Returns the mls/validatetrans constraint expression calculations in
+ * a buffer that must be free'd by the caller using free(3).
+ * If the SHOW_GRANTED flag is set it will show granted and denied
+ * mls/validatetrans (the default is to show only those denied).
+ */
+extern int sepol_validate_transition_reason_buffer(sepol_security_id_t oldsid,
+ sepol_security_id_t newsid,
+ sepol_security_id_t tasksid,
+ sepol_security_class_t tclass,
+ char **reason_buf,
+ unsigned int flags);
+
+/*
+ * Return a class ID associated with the class string representation
+ * specified by `class_name'.
+ */
+extern int sepol_string_to_security_class(const char *class_name,
+ sepol_security_class_t *tclass);
+
+/*
+ * Return a permission av bit associated with tclass and the string
+ * representation of the `perm_name'.
+ */
+extern int sepol_string_to_av_perm(sepol_security_class_t tclass,
+ const char *perm_name,
+ sepol_access_vector_t *av);
+
+/*
+ * Compute a SID to use for labeling a new object in the
+ * class `tclass' based on a SID pair.
+ */
+extern int sepol_transition_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Compute a SID to use when selecting a member of a
+ * polyinstantiated object of class `tclass' based on
+ * a SID pair.
+ */
+extern int sepol_member_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Compute a SID to use for relabeling an object in the
+ * class `tclass' based on a SID pair.
+ */
+extern int sepol_change_sid(sepol_security_id_t ssid, /* IN */
+ sepol_security_id_t tsid, /* IN */
+ sepol_security_class_t tclass, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Write the security context string representation of
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+extern int sepol_sid_to_context(sepol_security_id_t sid, /* IN */
+ sepol_security_context_t * scontext, /* OUT */
+ size_t * scontext_len); /* OUT */
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+extern int sepol_context_to_sid(const sepol_security_context_t scontext, /* IN */
+ size_t scontext_len, /* IN */
+ sepol_security_id_t * out_sid); /* OUT */
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated
+ * array containing the set of SIDs. Set `*nel' to the
+ * number of elements in the array.
+ */
+extern int sepol_get_user_sids(sepol_security_id_t callsid,
+ char *username,
+ sepol_security_id_t ** sids, uint32_t * nel);
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'. The `fs_sid' SID is returned for
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+extern int sepol_fs_sid(char *dev, /* IN */
+ sepol_security_id_t * fs_sid, /* OUT */
+ sepol_security_id_t * file_sid); /* OUT */
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+extern int sepol_port_sid(uint16_t domain,
+ uint16_t type,
+ uint8_t protocol,
+ uint16_t port, sepol_security_id_t * out_sid);
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'. The `if_sid' SID is returned for
+ * the interface and the `msg_sid' SID is returned as
+ * the default SID for messages received on the
+ * interface.
+ */
+extern int sepol_netif_sid(char *name,
+ sepol_security_id_t * if_sid,
+ sepol_security_id_t * msg_sid);
+
+/*
+ * Return the SID of the node specified by the address
+ * `addr' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+extern int sepol_node_sid(uint16_t domain,
+ void *addr,
+ size_t addrlen, sepol_security_id_t * out_sid);
+
+/*
+ * Return a value indicating how to handle labeling for the
+ * the specified filesystem type, and optionally return a SID
+ * for the filesystem object.
+ */
+#define SECURITY_FS_USE_XATTR 1 /* use xattr */
+#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
+#define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */
+#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
+#define SECURITY_FS_USE_NONE 5 /* no labeling support */
+extern int sepol_fs_use(const char *fstype, /* IN */
+ unsigned int *behavior, /* OUT */
+ sepol_security_id_t * sid); /* OUT */
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+extern int sepol_genfs_sid(const char *fstype, /* IN */
+ const char *name, /* IN */
+ sepol_security_class_t sclass, /* IN */
+ sepol_security_id_t * sid); /* OUT */
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/policydb/sidtab.h b/libsepol/include/sepol/policydb/sidtab.h
new file mode 100644
index 0000000..4b93567
--- /dev/null
+++ b/libsepol/include/sepol/policydb/sidtab.h
@@ -0,0 +1,75 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ */
+
+#ifndef _SEPOL_POLICYDB_SIDTAB_H_
+#define _SEPOL_POLICYDB_SIDTAB_H_
+
+#include <sepol/policydb/context.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct sidtab_node {
+ sepol_security_id_t sid; /* security identifier */
+ context_struct_t context; /* security context structure */
+ struct sidtab_node *next;
+} sidtab_node_t;
+
+typedef struct sidtab_node *sidtab_ptr_t;
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+typedef struct {
+ sidtab_ptr_t *htable;
+ unsigned int nel; /* number of elements */
+ unsigned int next_sid; /* next SID to allocate */
+ unsigned char shutdown;
+} sidtab_t;
+
+extern int sepol_sidtab_init(sidtab_t * s);
+
+extern int sepol_sidtab_insert(sidtab_t * s,
+ sepol_security_id_t sid,
+ context_struct_t * context);
+
+extern context_struct_t *sepol_sidtab_search(sidtab_t * s,
+ sepol_security_id_t sid);
+
+extern int sepol_sidtab_map(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args);
+
+extern void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+ int (*apply) (sepol_security_id_t
+ s,
+ context_struct_t *
+ context, void *args),
+ void *args);
+
+extern int sepol_sidtab_context_to_sid(sidtab_t * s, /* IN */
+ context_struct_t * context, /* IN */
+ sepol_security_id_t * sid); /* OUT */
+
+extern void sepol_sidtab_hash_eval(sidtab_t * h, char *tag);
+
+extern void sepol_sidtab_destroy(sidtab_t * s);
+
+extern void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src);
+
+extern void sepol_sidtab_shutdown(sidtab_t * s);
+
+__END_DECLS
+#endif /* _SIDTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/symtab.h b/libsepol/include/sepol/policydb/symtab.h
new file mode 100644
index 0000000..e0da337
--- /dev/null
+++ b/libsepol/include/sepol/policydb/symtab.h
@@ -0,0 +1,43 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * A symbol table (symtab) maintains associations between symbol
+ * strings and datum values. The type of the datum values
+ * is arbitrary. The symbol table type is implemented
+ * using the hash table type (hashtab).
+ */
+
+#ifndef _SEPOL_POLICYDB_SYMTAB_H_
+#define _SEPOL_POLICYDB_SYMTAB_H_
+
+#include <sepol/policydb/hashtab.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* The symtab_datum struct stores the common information for
+ * all symtab datums. It should the first element in every
+ * struct that will be used in a symtab to allow the specific
+ * datum types to be freely cast to this type.
+ *
+ * The values start at 1 - 0 is never a valid value.
+ */
+typedef struct symtab_datum {
+ uint32_t value;
+} symtab_datum_t;
+
+typedef struct {
+ hashtab_t table; /* hash table (keyed on a string) */
+ uint32_t nprim; /* number of primary names in table */
+} symtab_t;
+
+extern int symtab_init(symtab_t *, unsigned int size);
+extern void symtab_destroy(symtab_t *);
+
+__END_DECLS
+#endif /* _SYMTAB_H_ */
+
+/* FLASK */
diff --git a/libsepol/include/sepol/policydb/util.h b/libsepol/include/sepol/policydb/util.h
new file mode 100644
index 0000000..fa12661
--- /dev/null
+++ b/libsepol/include/sepol/policydb/util.h
@@ -0,0 +1,44 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SEPOL_UTIL_H__
+#define __SEPOL_UTIL_H__
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
+
+extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+ sepol_access_vector_t av);
+
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms);
+
+/*
+ * The tokenize function may be used to
+ * replace sscanf
+ */
+extern int tokenize(char *line_buf, char delim, int num_args, ...);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/port_record.h b/libsepol/include/sepol/port_record.h
new file mode 100644
index 0000000..c07d1fa
--- /dev/null
+++ b/libsepol/include/sepol/port_record.h
@@ -0,0 +1,71 @@
+#ifndef _SEPOL_PORT_RECORD_H_
+#define _SEPOL_PORT_RECORD_H_
+
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_port;
+struct sepol_port_key;
+typedef struct sepol_port sepol_port_t;
+typedef struct sepol_port_key sepol_port_key_t;
+
+#define SEPOL_PROTO_UDP 0
+#define SEPOL_PROTO_TCP 1
+#define SEPOL_PROTO_DCCP 2
+
+/* Key */
+extern int sepol_port_compare(const sepol_port_t * port,
+ const sepol_port_key_t * key);
+
+extern int sepol_port_compare2(const sepol_port_t * port,
+ const sepol_port_t * port2);
+
+extern int sepol_port_key_create(sepol_handle_t * handle,
+ int low, int high, int proto,
+ sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_unpack(const sepol_port_key_t * key,
+ int *low, int *high, int *proto);
+
+extern int sepol_port_key_extract(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_key_t ** key_ptr);
+
+extern void sepol_port_key_free(sepol_port_key_t * key);
+
+/* Protocol */
+extern int sepol_port_get_proto(const sepol_port_t * port);
+
+extern void sepol_port_set_proto(sepol_port_t * port, int proto);
+
+extern const char *sepol_port_get_proto_str(int proto);
+
+/* Port */
+extern int sepol_port_get_low(const sepol_port_t * port);
+
+extern int sepol_port_get_high(const sepol_port_t * port);
+
+extern void sepol_port_set_port(sepol_port_t * port, int port_num);
+
+extern void sepol_port_set_range(sepol_port_t * port, int low, int high);
+
+/* Context */
+extern sepol_context_t *sepol_port_get_con(const sepol_port_t * port);
+
+extern int sepol_port_set_con(sepol_handle_t * handle,
+ sepol_port_t * port, sepol_context_t * con);
+
+/* Create/Clone/Destroy */
+extern int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port_ptr);
+
+extern int sepol_port_clone(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_t ** port_ptr);
+
+extern void sepol_port_free(sepol_port_t * port);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/ports.h b/libsepol/include/sepol/ports.h
new file mode 100644
index 0000000..b4622ba
--- /dev/null
+++ b/libsepol/include/sepol/ports.h
@@ -0,0 +1,44 @@
+#ifndef _SEPOL_PORTS_H_
+#define _SEPOL_PORTS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/port_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if a port exists */
+extern int sepol_port_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_port_key_t * key, int *response);
+
+/* Query a port - returns the port, or NULL if not found */
+extern int sepol_port_query(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_port_key_t * key,
+ sepol_port_t ** response);
+
+/* Modify a port, or add it, if the key is not found */
+extern int sepol_port_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_port_key_t * key,
+ const sepol_port_t * data);
+
+/* Iterate the ports
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+
+extern int sepol_port_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_port_t * port,
+ void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/roles.h b/libsepol/include/sepol/roles.h
new file mode 100644
index 0000000..89b3af2
--- /dev/null
+++ b/libsepol/include/sepol/roles.h
@@ -0,0 +1,15 @@
+#ifndef _SEPOL_ROLES_H_
+#define _SEPOL_ROLES_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int sepol_role_exists(const sepol_policydb_t * policydb,
+ const char *role, int *response);
+
+extern int sepol_role_list(const sepol_policydb_t * policydb,
+ char ***roles, unsigned int *nroles);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/sepol.h b/libsepol/include/sepol/sepol.h
new file mode 100644
index 0000000..00a2129
--- /dev/null
+++ b/libsepol/include/sepol/sepol.h
@@ -0,0 +1,32 @@
+#ifndef _SEPOL_H_
+#define _SEPOL_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#include <sepol/user_record.h>
+#include <sepol/context_record.h>
+#include <sepol/iface_record.h>
+#include <sepol/port_record.h>
+#include <sepol/boolean_record.h>
+#include <sepol/node_record.h>
+
+#include <sepol/booleans.h>
+#include <sepol/interfaces.h>
+#include <sepol/ports.h>
+#include <sepol/nodes.h>
+#include <sepol/users.h>
+#include <sepol/handle.h>
+#include <sepol/debug.h>
+#include <sepol/policydb.h>
+#include <sepol/module.h>
+#include <sepol/context.h>
+
+/* Set internal policydb from a file for subsequent service calls. */
+extern int sepol_set_policydb_from_file(FILE * fp);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/user_record.h b/libsepol/include/sepol/user_record.h
new file mode 100644
index 0000000..9a39526
--- /dev/null
+++ b/libsepol/include/sepol/user_record.h
@@ -0,0 +1,80 @@
+#ifndef _SEPOL_USER_RECORD_H_
+#define _SEPOL_USER_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_user;
+struct sepol_user_key;
+typedef struct sepol_user sepol_user_t;
+typedef struct sepol_user_key sepol_user_key_t;
+
+/* Key */
+extern int sepol_user_key_create(sepol_handle_t * handle,
+ const char *name, sepol_user_key_t ** key);
+
+extern void sepol_user_key_unpack(const sepol_user_key_t * key,
+ const char **name);
+
+extern int sepol_user_key_extract(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_key_t ** key_ptr);
+
+extern void sepol_user_key_free(sepol_user_key_t * key);
+
+extern int sepol_user_compare(const sepol_user_t * user,
+ const sepol_user_key_t * key);
+
+extern int sepol_user_compare2(const sepol_user_t * user,
+ const sepol_user_t * user2);
+
+/* Name */
+extern const char *sepol_user_get_name(const sepol_user_t * user);
+
+extern int sepol_user_set_name(sepol_handle_t * handle,
+ sepol_user_t * user, const char *name);
+
+/* MLS */
+extern const char *sepol_user_get_mlslevel(const sepol_user_t * user);
+
+extern int sepol_user_set_mlslevel(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_level);
+
+extern const char *sepol_user_get_mlsrange(const sepol_user_t * user);
+
+extern int sepol_user_set_mlsrange(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_range);
+
+/* Role management */
+extern int sepol_user_get_num_roles(const sepol_user_t * user);
+
+extern int sepol_user_add_role(sepol_handle_t * handle,
+ sepol_user_t * user, const char *role);
+
+extern void sepol_user_del_role(sepol_user_t * user, const char *role);
+
+extern int sepol_user_has_role(const sepol_user_t * user, const char *role);
+
+extern int sepol_user_get_roles(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ const char ***roles_arr,
+ unsigned int *num_roles);
+
+extern int sepol_user_set_roles(sepol_handle_t * handle,
+ sepol_user_t * user,
+ const char **roles_arr, unsigned int num_roles);
+
+/* Create/Clone/Destroy */
+extern int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr);
+
+extern int sepol_user_clone(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_t ** user_ptr);
+
+extern void sepol_user_free(sepol_user_t * user);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/users.h b/libsepol/include/sepol/users.h
new file mode 100644
index 0000000..0e0f76e
--- /dev/null
+++ b/libsepol/include/sepol/users.h
@@ -0,0 +1,61 @@
+#ifndef _SEPOL_USERS_H_
+#define _SEPOL_USERS_H_
+
+#include <sepol/policydb.h>
+#include <sepol/user_record.h>
+#include <sepol/handle.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*---------compatibility------------*/
+
+/* Given an existing binary policy (starting at 'data with length 'len')
+ and user configurations living in 'usersdir', generate a new binary
+ policy for the new user configurations. Sets '*newdata' and '*newlen'
+ to refer to the new binary policy image. */
+extern int sepol_genusers(void *data, size_t len,
+ const char *usersdir,
+ void **newdata, size_t * newlen);
+
+/* Enable or disable deletion of users by sepol_genusers(3) when
+ a user in original binary policy image is not defined by the
+ new user configurations. Defaults to disabled. */
+extern void sepol_set_delusers(int on);
+
+/*--------end compatibility----------*/
+
+/* Modify the user, or add it, if the key is not found */
+extern int sepol_user_modify(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const sepol_user_key_t * key,
+ const sepol_user_t * data);
+
+/* Return the number of users */
+extern int sepol_user_count(sepol_handle_t * handle,
+ const sepol_policydb_t * p, unsigned int *response);
+
+/* Check if the specified user exists */
+extern int sepol_user_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_user_key_t * key, int *response);
+
+/* Query a user - returns the user or NULL if not found */
+extern int sepol_user_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key,
+ sepol_user_t ** response);
+
+/* Iterate the users
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue */
+extern int sepol_user_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ int (*fn) (const sepol_user_t * user,
+ void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/man/Makefile b/libsepol/man/Makefile
new file mode 100644
index 0000000..1192433
--- /dev/null
+++ b/libsepol/man/Makefile
@@ -0,0 +1,12 @@
+# Installation directories.
+MAN8DIR ?= $(DESTDIR)/usr/share/man/man8
+MAN3DIR ?= $(DESTDIR)/usr/share/man/man3
+
+all:
+
+install: all
+ mkdir -p $(MAN3DIR)
+ mkdir -p $(MAN8DIR)
+ install -m 644 man3/*.3 $(MAN3DIR)
+ install -m 644 man8/*.8 $(MAN8DIR)
+
diff --git a/libsepol/man/man3/sepol_check_context.3 b/libsepol/man/man3/sepol_check_context.3
new file mode 100644
index 0000000..4a3c57d
--- /dev/null
+++ b/libsepol/man/man3/sepol_check_context.3
@@ -0,0 +1,25 @@
+.TH "sepol_check_context" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_check_context \- Check the validity of a security context against a binary policy.
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_check_context(const char *" context ");"
+.sp
+.BI "int sepol_set_policydb_from_file(FILE *" fp ");"
+
+.SH "DESCRIPTION"
+.B sepol_check_context
+checks the validity of a security context against a binary policy
+previously loaded from a file via
+.B sepol_set_policydb_from_file.
+It is used by
+.B setfiles -c
+to validate a file contexts configuration against the binary policy
+upon policy builds. For validating a context against the active
+policy on a SELinux system, use
+.B security_check_context
+from libselinux instead.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 with errno set otherwise.
diff --git a/libsepol/man/man3/sepol_genbools.3 b/libsepol/man/man3/sepol_genbools.3
new file mode 100644
index 0000000..ca5b5a6
--- /dev/null
+++ b/libsepol/man/man3/sepol_genbools.3
@@ -0,0 +1,30 @@
+.TH "sepol_genbools" "3" "11 August 2004" "sds@epoch.ncsc.mil" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genbools(void *" data ", size_t "len ", char *" boolpath );
+.br
+.BI "int sepol_genbools_array(void *" data ", size_t " len ", char **" names ", int *" values ", int " nel );
+
+.SH "DESCRIPTION"
+.B sepol_genbools
+rewrites a binary policy stored in the memory region described by
+(data, len) to use the boolean settings specified in the file named by
+boolpath. The boolean settings are specified by name=value lines
+where value may be 0 or false to disable or 1 or true to enable. The
+binary policy is rewritten in place in memory.
+
+.B sepol_genbools_array
+does likewise, but obtains the boolean settings from the parallel arrays
+(names, values) with nel elements each.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that the boolean file did not exist.
+An errno of EINVAL indicates that one or more booleans listed in the
+boolean file was undefined in the policy or had an invalid value specified;
+in this case, the binary policy is still rewritten but any invalid
+boolean settings are ignored.
+
diff --git a/libsepol/man/man3/sepol_genusers.3 b/libsepol/man/man3/sepol_genusers.3
new file mode 100644
index 0000000..1f820ff
--- /dev/null
+++ b/libsepol/man/man3/sepol_genusers.3
@@ -0,0 +1,54 @@
+.TH "sepol_genusers" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation"
+.SH "NAME"
+sepol_genusers \- Generate a new binary policy image with a customized user configuration
+.SH "SYNOPSIS"
+.B #include <sepol/sepol.h>
+.sp
+.BI "int sepol_genusers(void *" data ", size_t "len ", const char *" usersdir ", void *" newdata ", size_t *" newlen);
+.sp
+.BI "void sepol_set_delusers(int " on ");"
+
+.SH "DESCRIPTION"
+.B sepol_genusers
+generates a new binary policy image from
+an existing binary policy image stored in the memory region described by
+the starting address
+.I data
+and the length
+.I len
+and a pair of user configuration files named
+.B system.users
+and
+.B local.users
+from the directory specified by
+.I usersdir.
+The resulting binary policy is placed into dynamically allocated
+memory and the variables
+.I newdata
+and
+.I newlen
+are set to refer to the new binary image's starting address and length.
+The original binary policy image is not modified.
+
+By default,
+.B sepol_genusers
+will preserve user entries that are defined in the original binary policy image
+but not defined in the user configuration files. If such user entries
+should instead by omitted entirely from the new binary policy image, then
+the
+.B sepol_set_delusers
+function may be called with
+.I on
+set to 1 prior to calling
+.B sepol_genusers
+in order to enable deletion of such users.
+
+.SH "RETURN VALUE"
+Returns 0 on success or \-1 otherwise, with errno set appropriately.
+An errno of ENOENT indicates that one or both of the user
+configuration files did not exist. An errno of EINVAL indicates that
+either the original binary policy image or the generated one were
+invalid. An errno of ENOMEM indicates that insufficient memory was
+available to process the original binary policy image or to generate
+the new policy image. Invalid entries in the user configuration files
+are skipped with a warning.
diff --git a/libsepol/man/man8/chkcon.8 b/libsepol/man/man8/chkcon.8
new file mode 100644
index 0000000..f8d75df
--- /dev/null
+++ b/libsepol/man/man8/chkcon.8
@@ -0,0 +1,41 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH CHKCON 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+chkcon \- determine if a security context is valid for a given binary policy
+.SH SYNOPSIS
+chkcon policy_file context
+.SH DESCRIPTION
+This utility validates (the string representation of) a security context
+specified by the argument
+.I context
+against configuration data read in from a policy database binary
+representation file specified by the argument
+.I policy_file.
+.SH FILES
+policy file
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
+
diff --git a/libsepol/man/man8/genpolbools.8 b/libsepol/man/man8/genpolbools.8
new file mode 100644
index 0000000..afeaced
--- /dev/null
+++ b/libsepol/man/man8/genpolbools.8
@@ -0,0 +1,16 @@
+.TH "genpolbools" "8" "11 August 2004" "sds@epoch.ncsc.mil" "SELinux Command Line documentation"
+.SH "NAME"
+genpolbools \- Rewrite a binary policy with different boolean settings
+.SH "SYNOPSIS"
+.B genpolbools oldpolicy booleans newpolicy
+
+.SH "DESCRIPTION"
+.B genpolbools
+rewrites an existing binary policy with different boolean settings,
+generating a new binary policy. The booleans file specifies the
+different boolean settings using name=value lines, where value
+can be 0 or false to disable the boolean or 1 or true to enable it.
+
+
+
+
diff --git a/libsepol/man/man8/genpolusers.8 b/libsepol/man/man8/genpolusers.8
new file mode 100644
index 0000000..34d729a
--- /dev/null
+++ b/libsepol/man/man8/genpolusers.8
@@ -0,0 +1,42 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org>
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH GENPOLUSERS 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation"
+.SH NAME
+genpolusers \- Generate new binary policy with updated user configuration
+.SH SYNOPSIS
+genpolusers in-policy usersdir out-policy
+.SH DESCRIPTION
+Given an existing binary policy file
+.I in\-policy,
+generate a new binary policy
+.I out\-policy
+with an updated user configuration based on any
+.B system.users
+and
+.B local.users
+files in the specified
+.I usersdir.
+.SH AUTHOR
+This manual page (and just the manual page) was written by Manoj
+Srivastava <srivasta@debian.org>.
diff --git a/libsepol/src/Makefile b/libsepol/src/Makefile
new file mode 100644
index 0000000..c0c3274
--- /dev/null
+++ b/libsepol/src/Makefile
@@ -0,0 +1,83 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+INCLUDEDIR ?= $(PREFIX)/include
+LIBDIR ?= $(PREFIX)/lib
+SHLIBDIR ?= $(DESTDIR)/lib
+RANLIB ?= ranlib
+LIBBASE ?= $(shell basename $(LIBDIR))
+CILDIR ?= ../cil
+
+VERSION = $(shell cat ../VERSION)
+LIBVERSION = 1
+
+LEX = flex
+CIL_GENERATED = $(CILDIR)/src/cil_lexer.c
+
+LIBA=libsepol.a
+TARGET=libsepol.so
+LIBPC=libsepol.pc
+LIBMAP=libsepol.map
+LIBSO=$(TARGET).$(LIBVERSION)
+OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
+LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
+CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-format-attribute -O2
+
+override CFLAGS += -I. -I../include -D_GNU_SOURCE
+
+ifneq ($(DISABLE_CIL),y)
+OBJS += $(sort $(patsubst %.c,%.o,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED)))
+LOBJS += $(sort $(patsubst %.c,%.lo,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED)))
+override CFLAGS += -I$(CILDIR)/include
+endif
+
+
+all: $(LIBA) $(LIBSO) $(LIBPC)
+
+
+$(LIBA): $(OBJS)
+ $(AR) rcs $@ $^
+ $(RANLIB) $@
+
+$(LIBSO): $(LOBJS) $(LIBMAP)
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $(LOBJS) -Wl,-soname,$(LIBSO),--version-script=$(LIBMAP),-z,defs
+ ln -sf $@ $(TARGET)
+
+$(LIBPC): $(LIBPC).in ../VERSION
+ sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@
+
+$(LIBMAP): $(LIBMAP).in
+ifneq ($(DISABLE_CIL),y)
+ cp $< $@
+else
+ sed -e '/^\s*cil_/d' < $< > $@
+endif
+
+ifneq ($(DISABLE_CIL),y)
+$(CILDIR)/src/cil_lexer.c: $(CILDIR)/src/cil_lexer.l
+ $(LEX) -t $< > $@
+endif
+
+%.o: %.c
+ $(CC) $(CFLAGS) -fPIC -c -o $@ $<
+
+%.lo: %.c
+ $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $<
+
+install: all
+ test -d $(LIBDIR) || install -m 755 -d $(LIBDIR)
+ install -m 644 $(LIBA) $(LIBDIR)
+ test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR)
+ install -m 755 $(LIBSO) $(SHLIBDIR)
+ test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig
+ install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig
+ ln -sf --relative $(SHLIBDIR)/$(LIBSO) $(LIBDIR)/$(TARGET)
+
+relabel:
+ /sbin/restorecon $(SHLIBDIR)/$(LIBSO)
+
+clean:
+ -rm -f $(LIBPC) $(LIBMAP) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) $(CIL_GENERATED)
+
+indent:
+ ../../scripts/Lindent $(wildcard *.[ch])
+
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
new file mode 100644
index 0000000..a4be880
--- /dev/null
+++ b/libsepol/src/assertion.c
@@ -0,0 +1,556 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Assertion checker for avtab entries, taken from
+ * checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "private.h"
+#include "debug.h"
+
+struct avtab_match_args {
+ sepol_handle_t *handle;
+ policydb_t *p;
+ avrule_t *avrule;
+ avtab_t *avtab;
+ unsigned long errors;
+};
+
+static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
+ unsigned int stype, unsigned int ttype,
+ const class_perm_node_t *curperm, uint32_t perms)
+{
+ if (avrule->source_filename) {
+ ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };",
+ avrule->source_line, avrule->source_filename, avrule->line,
+ p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->tclass - 1],
+ sepol_av_to_string(p, curperm->tclass, perms));
+ } else if (avrule->line) {
+ ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
+ avrule->line, p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->tclass - 1],
+ sepol_av_to_string(p, curperm->tclass, perms));
+ } else {
+ ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
+ p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->tclass - 1],
+ sepol_av_to_string(p, curperm->tclass, perms));
+ }
+}
+
+static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
+{
+ for (; cp; cp = cp->next) {
+ if ((cp->tclass == class) && (cp->data & data)) {
+ break;
+ }
+ }
+ if (!cp)
+ return 0;
+
+ return 1;
+}
+
+static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
+ size_t i;
+ for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
+ if (perms1[i] & perms2[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_extended_permissions(av_extended_perms_t *neverallow, avtab_extended_perms_t *allow)
+{
+ int rc = 0;
+ if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+ && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+ if (neverallow->driver == allow->driver)
+ rc = extended_permissions_and(neverallow->perms, allow->perms);
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+ && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+ rc = xperm_test(neverallow->driver, allow->perms);
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+ && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+ rc = xperm_test(allow->driver, neverallow->perms);
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+ && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+ rc = extended_permissions_and(neverallow->perms, allow->perms);
+ }
+
+ return rc;
+}
+
+/* Compute which allowed extended permissions violate the neverallow rule */
+static void extended_permissions_violated(avtab_extended_perms_t *result,
+ av_extended_perms_t *neverallow,
+ avtab_extended_perms_t *allow)
+{
+ size_t i;
+ if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+ && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+ result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+ result->driver = allow->driver;
+ for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+ result->perms[i] = neverallow->perms[i] & allow->perms[i];
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+ && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+ result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+ result->driver = neverallow->driver;
+ memcpy(result->perms, neverallow->perms, sizeof(result->perms));
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+ && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+ result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+ result->driver = allow->driver;
+ memcpy(result->perms, allow->perms, sizeof(result->perms));
+ } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+ && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+ result->specified = AVTAB_XPERMS_IOCTLDRIVER;
+ for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+ result->perms[i] = neverallow->perms[i] & allow->perms[i];
+ }
+}
+
+/* Same scenarios of interest as check_assertion_extended_permissions */
+static int report_assertion_extended_permissions(sepol_handle_t *handle,
+ policydb_t *p, const avrule_t *avrule,
+ unsigned int stype, unsigned int ttype,
+ const class_perm_node_t *curperm, uint32_t perms,
+ avtab_key_t *k, avtab_t *avtab)
+{
+ avtab_ptr_t node;
+ avtab_key_t tmp_key;
+ avtab_extended_perms_t *xperms;
+ avtab_extended_perms_t error;
+ ebitmap_t *sattr = &p->type_attr_map[stype];
+ ebitmap_t *tattr = &p->type_attr_map[ttype];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ int rc = 1;
+ int ret = 0;
+
+ memcpy(&tmp_key, k, sizeof(avtab_key_t));
+ tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ tmp_key.source_type = i + 1;
+ tmp_key.target_type = j + 1;
+ for (node = avtab_search_node(avtab, &tmp_key);
+ node;
+ node = avtab_search_node_next(node, tmp_key.specified)) {
+ xperms = node->datum.xperms;
+ if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+ && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+ continue;
+
+ rc = check_extended_permissions(avrule->xperms, xperms);
+ /* failure on the extended permission check_extended_permissions */
+ if (rc) {
+ extended_permissions_violated(&error, avrule->xperms, xperms);
+ ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+ "allowxperm %s %s:%s %s;",
+ avrule->source_line, avrule->source_filename, avrule->line,
+ p->p_type_val_to_name[i],
+ p->p_type_val_to_name[j],
+ p->p_class_val_to_name[curperm->tclass - 1],
+ sepol_extended_perms_to_string(&error));
+
+ rc = 0;
+ ret++;
+ }
+ }
+ }
+ }
+
+ /* failure on the regular permissions */
+ if (rc) {
+ ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+ "allow %s %s:%s {%s };",
+ avrule->source_line, avrule->source_filename, avrule->line,
+ p->p_type_val_to_name[stype],
+ p->p_type_val_to_name[ttype],
+ p->p_class_val_to_name[curperm->tclass - 1],
+ sepol_av_to_string(p, curperm->tclass, perms));
+ ret++;
+
+ }
+
+ return ret;
+}
+
+static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
+{
+ int rc = 0;
+ struct avtab_match_args *a = (struct avtab_match_args *)args;
+ sepol_handle_t *handle = a->handle;
+ policydb_t *p = a->p;
+ avtab_t *avtab = a->avtab;
+ avrule_t *avrule = a->avrule;
+ class_perm_node_t *cp;
+ uint32_t perms;
+ ebitmap_t src_matches, tgt_matches, matches;
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+
+ if (k->specified != AVTAB_ALLOWED)
+ return 0;
+
+ if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
+ return 0;
+
+ ebitmap_init(&src_matches);
+ ebitmap_init(&tgt_matches);
+ ebitmap_init(&matches);
+
+ rc = ebitmap_and(&src_matches, &avrule->stypes.types,
+ &p->attr_type_map[k->source_type - 1]);
+ if (rc)
+ goto oom;
+
+ if (ebitmap_length(&src_matches) == 0)
+ goto exit;
+
+ if (avrule->flags == RULE_SELF) {
+ rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]);
+ if (rc)
+ goto oom;
+ rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
+ if (rc)
+ goto oom;
+ } else {
+ rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
+ if (rc)
+ goto oom;
+ }
+
+ if (ebitmap_length(&tgt_matches) == 0)
+ goto exit;
+
+ for (cp = avrule->perms; cp; cp = cp->next) {
+
+ perms = cp->data & d->data;
+ if ((cp->tclass != k->target_class) || !perms) {
+ continue;
+ }
+
+ ebitmap_for_each_bit(&src_matches, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&tgt_matches, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+
+ if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+ a->errors += report_assertion_extended_permissions(handle,p, avrule,
+ i, j, cp, perms, k, avtab);
+ } else {
+ a->errors++;
+ report_failure(handle, p, avrule, i, j, cp, perms);
+ }
+ }
+ }
+ }
+ goto exit;
+
+oom:
+ ERR(NULL, "Out of memory - unable to check neverallows");
+
+exit:
+ ebitmap_destroy(&src_matches);
+ ebitmap_destroy(&tgt_matches);
+ ebitmap_destroy(&matches);
+ return rc;
+}
+
+int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
+{
+ int rc;
+ struct avtab_match_args args;
+
+ args.handle = handle;
+ args.p = p;
+ args.avrule = avrule;
+ args.errors = 0;
+
+ rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
+ if (rc)
+ goto oom;
+
+ rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
+ if (rc)
+ goto oom;
+
+ return args.errors;
+
+oom:
+ return rc;
+}
+
+/*
+ * Look up the extended permissions in avtab and verify that neverallowed
+ * permissions are not granted.
+ */
+static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t *avtab,
+ unsigned int stype, unsigned int ttype,
+ avtab_key_t *k, policydb_t *p)
+{
+ avtab_ptr_t node;
+ avtab_key_t tmp_key;
+ avtab_extended_perms_t *xperms;
+ av_extended_perms_t *neverallow_xperms = avrule->xperms;
+ ebitmap_t *sattr = &p->type_attr_map[stype];
+ ebitmap_t *tattr = &p->type_attr_map[ttype];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ int rc = 1;
+
+ memcpy(&tmp_key, k, sizeof(avtab_key_t));
+ tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ tmp_key.source_type = i + 1;
+ tmp_key.target_type = j + 1;
+ for (node = avtab_search_node(avtab, &tmp_key);
+ node;
+ node = avtab_search_node_next(node, tmp_key.specified)) {
+ xperms = node->datum.xperms;
+
+ if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+ && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+ continue;
+ rc = check_extended_permissions(neverallow_xperms, xperms);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * When the ioctl permission is granted on an avtab entry that matches an
+ * avrule neverallowxperm entry, enumerate over the matching
+ * source/target/class sets to determine if the extended permissions exist
+ * and if the neverallowed ioctls are granted.
+ *
+ * Four scenarios of interest:
+ * 1. PASS - the ioctl permission is not granted for this source/target/class
+ * This case is handled in check_assertion_avtab_match
+ * 2. PASS - The ioctl permission is granted AND the extended permission
+ * is NOT granted
+ * 3. FAIL - The ioctl permission is granted AND no extended permissions
+ * exist
+ * 4. FAIL - The ioctl permission is granted AND the extended permission is
+ * granted
+ */
+static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
+ avtab_key_t *k, policydb_t *p)
+{
+ ebitmap_t src_matches, tgt_matches, matches;
+ unsigned int i, j;
+ ebitmap_node_t *snode, *tnode;
+ class_perm_node_t *cp;
+ int rc;
+ int ret = 1;
+
+ ebitmap_init(&src_matches);
+ ebitmap_init(&tgt_matches);
+ ebitmap_init(&matches);
+ rc = ebitmap_and(&src_matches, &avrule->stypes.types,
+ &p->attr_type_map[k->source_type - 1]);
+ if (rc)
+ goto oom;
+
+ if (ebitmap_length(&src_matches) == 0)
+ goto exit;
+
+ if (avrule->flags == RULE_SELF) {
+ rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1],
+ &p->attr_type_map[k->target_type - 1]);
+ if (rc)
+ goto oom;
+ rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
+ if (rc)
+ goto oom;
+ } else {
+ rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types,
+ &p->attr_type_map[k->target_type -1]);
+ if (rc)
+ goto oom;
+ }
+
+ if (ebitmap_length(&tgt_matches) == 0)
+ goto exit;
+
+ for (cp = avrule->perms; cp; cp = cp->next) {
+ if (cp->tclass != k->target_class)
+ continue;
+ ebitmap_for_each_bit(&src_matches, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&tgt_matches, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+
+ ret = check_assertion_extended_permissions_avtab(
+ avrule, avtab, i, j, k, p);
+ if (ret)
+ goto exit;
+ }
+ }
+ }
+ goto exit;
+
+oom:
+ ERR(NULL, "Out of memory - unable to check neverallows");
+
+exit:
+ ebitmap_destroy(&src_matches);
+ ebitmap_destroy(&tgt_matches);
+ ebitmap_destroy(&matches);
+ return ret;
+}
+
+static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
+{
+ int rc;
+ struct avtab_match_args *a = (struct avtab_match_args *)args;
+ policydb_t *p = a->p;
+ avrule_t *avrule = a->avrule;
+ avtab_t *avtab = a->avtab;
+
+ if (k->specified != AVTAB_ALLOWED)
+ goto exit;
+
+ if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
+ goto exit;
+
+ rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
+ if (rc == 0)
+ goto exit;
+
+ if (avrule->flags == RULE_SELF) {
+ /* If the neverallow uses SELF, then it is not enough that the
+ * neverallow's source matches the src and tgt of the rule being checked.
+ * It must match the same thing in the src and tgt, so AND the source
+ * and target together and check for a match on the result.
+ */
+ ebitmap_t match;
+ rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] );
+ if (rc) {
+ ebitmap_destroy(&match);
+ goto oom;
+ }
+ rc = ebitmap_match_any(&avrule->stypes.types, &match);
+ ebitmap_destroy(&match);
+ } else {
+ rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
+ }
+ if (rc == 0)
+ goto exit;
+
+ if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+ rc = check_assertion_extended_permissions(avrule, avtab, k, p);
+ if (rc == 0)
+ goto exit;
+ }
+ return 1;
+
+exit:
+ return 0;
+
+oom:
+ ERR(NULL, "Out of memory - unable to check neverallows");
+ return rc;
+}
+
+int check_assertion(policydb_t *p, avrule_t *avrule)
+{
+ int rc;
+ struct avtab_match_args args;
+
+ args.handle = NULL;
+ args.p = p;
+ args.avrule = avrule;
+ args.errors = 0;
+ args.avtab = &p->te_avtab;
+
+ rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
+
+ if (rc == 0) {
+ args.avtab = &p->te_cond_avtab;
+ rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
+ }
+
+ return rc;
+}
+
+int check_assertions(sepol_handle_t * handle, policydb_t * p,
+ avrule_t * avrules)
+{
+ int rc;
+ avrule_t *a;
+ unsigned long errors = 0;
+
+ if (!avrules) {
+ /* Since assertions are stored in avrules, if it is NULL
+ there won't be any to check. This also prevents an invalid
+ free if the avtabs are never initialized */
+ return 0;
+ }
+
+ for (a = avrules; a != NULL; a = a->next) {
+ if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
+ continue;
+ rc = check_assertion(p, a);
+ if (rc) {
+ rc = report_assertion_failures(handle, p, a);
+ if (rc < 0) {
+ ERR(handle, "Error occurred while checking neverallows");
+ return -1;
+ }
+ errors += rc;
+ }
+ }
+
+ if (errors)
+ ERR(handle, "%lu neverallow failures occurred", errors);
+
+ return errors ? -1 : 0;
+}
diff --git a/libsepol/src/av_permissions.h b/libsepol/src/av_permissions.h
new file mode 100644
index 0000000..97278ed
--- /dev/null
+++ b/libsepol/src/av_permissions.h
@@ -0,0 +1,3 @@
+/* Used by security_compute_av. */
+#define PROCESS__TRANSITION 0x00000002UL
+#define PROCESS__DYNTRANSITION 0x00800000UL
diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c
new file mode 100644
index 0000000..84cfaf8
--- /dev/null
+++ b/libsepol/src/avrule_block.c
@@ -0,0 +1,201 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Functions that manipulate a logical block (conditional, optional,
+ * or global scope) for a policy module.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+/* It is anticipated that there be less declarations within an avrule
+ * block than the global policy. Thus the symbol table sizes are
+ * smaller than those listed in policydb.c */
+static unsigned int symtab_sizes[SYM_NUM] = {
+ 2,
+ 4,
+ 8,
+ 32,
+ 16,
+ 4,
+ 2,
+ 2,
+};
+
+avrule_block_t *avrule_block_create(void)
+{
+ avrule_block_t *block;
+ if ((block = calloc(1, sizeof(*block))) == NULL) {
+ return NULL;
+ }
+ return block;
+}
+
+avrule_decl_t *avrule_decl_create(uint32_t decl_id)
+{
+ avrule_decl_t *decl;
+ int i;
+ if ((decl = calloc(1, sizeof(*decl))) == NULL) {
+ return NULL;
+ }
+ decl->decl_id = decl_id;
+ for (i = 0; i < SYM_NUM; i++) {
+ if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
+ avrule_decl_destroy(decl);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_init(&decl->required.scope[i]);
+ ebitmap_init(&decl->declared.scope[i]);
+ }
+ return decl;
+}
+
+/* note that unlike the other destroy functions, this one does /NOT/
+ * destroy the pointer itself */
+static void scope_index_destroy(scope_index_t * scope)
+{
+ unsigned int i;
+ if (scope == NULL) {
+ return;
+ }
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_destroy(scope->scope + i);
+ }
+ for (i = 0; i < scope->class_perms_len; i++) {
+ ebitmap_destroy(scope->class_perms_map + i);
+ }
+ free(scope->class_perms_map);
+}
+
+void avrule_decl_destroy(avrule_decl_t * x)
+{
+ if (x == NULL) {
+ return;
+ }
+ cond_list_destroy(x->cond_list);
+ avrule_list_destroy(x->avrules);
+ role_trans_rule_list_destroy(x->role_tr_rules);
+ filename_trans_rule_list_destroy(x->filename_trans_rules);
+ role_allow_rule_list_destroy(x->role_allow_rules);
+ range_trans_rule_list_destroy(x->range_tr_rules);
+ scope_index_destroy(&x->required);
+ scope_index_destroy(&x->declared);
+ symtabs_destroy(x->symtab);
+ free(x->module_name);
+ free(x);
+}
+
+void avrule_block_destroy(avrule_block_t * x)
+{
+ avrule_decl_t *decl;
+ if (x == NULL) {
+ return;
+ }
+ decl = x->branch_list;
+ while (decl != NULL) {
+ avrule_decl_t *next_decl = decl->next;
+ avrule_decl_destroy(decl);
+ decl = next_decl;
+ }
+ free(x);
+}
+
+void avrule_block_list_destroy(avrule_block_t * x)
+{
+ while (x != NULL) {
+ avrule_block_t *next = x->next;
+ avrule_block_destroy(x);
+ x = next;
+ }
+}
+
+/* Get a conditional node from a avrule_decl with the same expression.
+ * If that expression does not exist then create one. */
+cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl,
+ cond_list_t * cond)
+{
+ cond_list_t *result;
+ int was_created;
+ result = cond_node_find(p, cond, decl->cond_list, &was_created);
+ if (result != NULL && was_created) {
+ result->next = decl->cond_list;
+ decl->cond_list = result;
+ }
+ return result;
+}
+
+/* Look up an identifier in a policy's scoping table. If it is there,
+ * marked as SCOPE_DECL, and any of its declaring block has been enabled,
+ * then return 1. Otherwise return 0. Can only be called after the
+ * decl_val_to_struct index has been created */
+int is_id_enabled(char *id, policydb_t * p, int symbol_table)
+{
+ scope_datum_t *scope =
+ (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id);
+ uint32_t i;
+ if (scope == NULL) {
+ return 0;
+ }
+ if (scope->scope != SCOPE_DECL) {
+ return 0;
+ }
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ avrule_decl_t *decl =
+ p->decl_val_to_struct[scope->decl_ids[i] - 1];
+ if (decl != NULL && decl->enabled) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Check if a particular permission is present within the given class,
+ * and that the class is enabled. Returns 1 if both conditions are
+ * true, 0 if neither could be found or if the class id disabled. */
+int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p)
+{
+ class_datum_t *cladatum;
+ perm_datum_t *perm;
+ if (!is_id_enabled(class_id, p, SYM_CLASSES)) {
+ return 0;
+ }
+ cladatum =
+ (class_datum_t *) hashtab_search(p->p_classes.table, class_id);
+ if (cladatum == NULL) {
+ return 0;
+ }
+ perm = hashtab_search(cladatum->permissions.table, perm_id);
+ if (perm == NULL && cladatum->comdatum != 0) {
+ /* permission was not in this class. before giving
+ * up, check the class's parent */
+ perm =
+ hashtab_search(cladatum->comdatum->permissions.table,
+ perm_id);
+ }
+ if (perm == NULL) {
+ return 0;
+ }
+ return 1;
+}
diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
new file mode 100644
index 0000000..3854d6f
--- /dev/null
+++ b/libsepol/src/avtab.c
@@ -0,0 +1,626 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Tuned number of hash slots for avtab to reduce memory usage
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Code cleanup
+ *
+ * Updated: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ * Copyright (C) 2003,2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the access vector table type.
+ */
+
+#include <stdlib.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/errcodes.h>
+
+#include "debug.h"
+#include "private.h"
+
+/* Based on MurmurHash3, written by Austin Appleby and placed in the
+ * public domain.
+ */
+static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask)
+{
+ static const uint32_t c1 = 0xcc9e2d51;
+ static const uint32_t c2 = 0x1b873593;
+ static const uint32_t r1 = 15;
+ static const uint32_t r2 = 13;
+ static const uint32_t m = 5;
+ static const uint32_t n = 0xe6546b64;
+
+ uint32_t hash = 0;
+
+#define mix(input) { \
+ uint32_t v = input; \
+ v *= c1; \
+ v = (v << r1) | (v >> (32 - r1)); \
+ v *= c2; \
+ hash ^= v; \
+ hash = (hash << r2) | (hash >> (32 - r2)); \
+ hash = hash * m + n; \
+}
+
+ mix(keyp->target_class);
+ mix(keyp->target_type);
+ mix(keyp->source_type);
+
+#undef mix
+
+ hash ^= hash >> 16;
+ hash *= 0x85ebca6b;
+ hash ^= hash >> 13;
+ hash *= 0xc2b2ae35;
+ hash ^= hash >> 16;
+
+ return hash & mask;
+}
+
+static avtab_ptr_t
+avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
+ avtab_datum_t * datum)
+{
+ avtab_ptr_t newnode;
+ avtab_extended_perms_t *xperms;
+
+ newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
+ if (newnode == NULL)
+ return NULL;
+ memset(newnode, 0, sizeof(struct avtab_node));
+ newnode->key = *key;
+
+ if (key->specified & AVTAB_XPERMS) {
+ xperms = calloc(1, sizeof(avtab_extended_perms_t));
+ if (xperms == NULL) {
+ free(newnode);
+ return NULL;
+ }
+ if (datum->xperms) /* else caller populates xperms */
+ *xperms = *(datum->xperms);
+
+ newnode->datum.xperms = xperms;
+ /* data is usually ignored with xperms, except in the case of
+ * neverallow checking, which requires permission bits to be set.
+ * So copy data so it is set in the avtab
+ */
+ newnode->datum.data = datum->data;
+ } else {
+ newnode->datum = *datum;
+ }
+
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+
+ h->nel++;
+ return newnode;
+}
+
+int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+ int hvalue;
+ avtab_ptr_t prev, cur, newnode;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return SEPOL_ENOMEM;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (prev = NULL, cur = h->htable[hvalue];
+ cur; prev = cur, cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified)) {
+ /* Extended permissions are not necessarily unique */
+ if (specified & AVTAB_XPERMS)
+ break;
+ return SEPOL_EEXIST;
+ }
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+ if (!newnode)
+ return SEPOL_ENOMEM;
+
+ return 0;
+}
+
+/* Unlike avtab_insert(), this function allow multiple insertions of the same
+ * key/specified mask into the table, as needed by the conditional avtab.
+ * It also returns a pointer to the node inserted.
+ */
+avtab_ptr_t
+avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
+{
+ int hvalue;
+ avtab_ptr_t prev, cur, newnode;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+ hvalue = avtab_hash(key, h->mask);
+ for (prev = NULL, cur = h->htable[hvalue];
+ cur; prev = cur, cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ break;
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
+
+ return newnode;
+}
+
+avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key)
+{
+ int hvalue;
+ avtab_ptr_t cur;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return &cur->datum;
+
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+
+ return NULL;
+}
+
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key)
+{
+ int hvalue;
+ avtab_ptr_t cur;
+ uint16_t specified =
+ key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (!h || !h->htable)
+ return NULL;
+
+ hvalue = avtab_hash(key, h->mask);
+ for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return cur;
+
+ if (key->source_type < cur->key.source_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type < cur->key.target_type)
+ break;
+ if (key->source_type == cur->key.source_type &&
+ key->target_type == cur->key.target_type &&
+ key->target_class < cur->key.target_class)
+ break;
+ }
+ return NULL;
+}
+
+avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified)
+{
+ avtab_ptr_t cur;
+
+ if (!node)
+ return NULL;
+
+ specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+ for (cur = node->next; cur; cur = cur->next) {
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type == cur->key.target_type &&
+ node->key.target_class == cur->key.target_class &&
+ (specified & cur->key.specified))
+ return cur;
+
+ if (node->key.source_type < cur->key.source_type)
+ break;
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type < cur->key.target_type)
+ break;
+ if (node->key.source_type == cur->key.source_type &&
+ node->key.target_type == cur->key.target_type &&
+ node->key.target_class < cur->key.target_class)
+ break;
+ }
+ return NULL;
+}
+
+void avtab_destroy(avtab_t * h)
+{
+ unsigned int i;
+ avtab_ptr_t cur, temp;
+
+ if (!h || !h->htable)
+ return;
+
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ if (cur->key.specified & AVTAB_XPERMS) {
+ free(cur->datum.xperms);
+ }
+ temp = cur;
+ cur = cur->next;
+ free(temp);
+ }
+ h->htable[i] = NULL;
+ }
+ free(h->htable);
+ h->htable = NULL;
+ h->nslot = 0;
+ h->mask = 0;
+}
+
+int avtab_map(avtab_t * h,
+ int (*apply) (avtab_key_t * k,
+ avtab_datum_t * d, void *args), void *args)
+{
+ unsigned int i;
+ int ret;
+ avtab_ptr_t cur;
+
+ if (!h)
+ return 0;
+
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(&cur->key, &cur->datum, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+int avtab_init(avtab_t * h)
+{
+ h->htable = NULL;
+ h->nel = 0;
+ return 0;
+}
+
+int avtab_alloc(avtab_t *h, uint32_t nrules)
+{
+ uint32_t mask = 0;
+ uint32_t shift = 0;
+ uint32_t work = nrules;
+ uint32_t nslot = 0;
+
+ if (nrules == 0)
+ goto out;
+
+ while (work) {
+ work = work >> 1;
+ shift++;
+ }
+ if (shift > 2)
+ shift = shift - 2;
+ nslot = 1 << shift;
+ if (nslot > MAX_AVTAB_HASH_BUCKETS)
+ nslot = MAX_AVTAB_HASH_BUCKETS;
+ mask = nslot - 1;
+
+ h->htable = calloc(nslot, sizeof(avtab_ptr_t));
+ if (!h->htable)
+ return -1;
+out:
+ h->nel = 0;
+ h->nslot = nslot;
+ h->mask = mask;
+ return 0;
+}
+
+void avtab_hash_eval(avtab_t * h, char *tag)
+{
+ unsigned int i, chain_len, slots_used, max_chain_len;
+ avtab_ptr_t cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < h->nslot; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len);
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+ AVTAB_ALLOWED,
+ AVTAB_AUDITDENY,
+ AVTAB_AUDITALLOW,
+ AVTAB_TRANSITION,
+ AVTAB_CHANGE,
+ AVTAB_MEMBER,
+ AVTAB_XPERMS_ALLOWED,
+ AVTAB_XPERMS_AUDITALLOW,
+ AVTAB_XPERMS_DONTAUDIT
+};
+
+int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
+ int (*insertf) (avtab_t * a, avtab_key_t * k,
+ avtab_datum_t * d, void *p), void *p)
+{
+ uint8_t buf8;
+ uint16_t buf16[4], enabled;
+ uint32_t buf32[8], items, items2, val;
+ avtab_key_t key;
+ avtab_datum_t datum;
+ avtab_extended_perms_t xperms;
+ unsigned set;
+ unsigned int i;
+ int rc;
+
+ memset(&key, 0, sizeof(avtab_key_t));
+ memset(&datum, 0, sizeof(avtab_datum_t));
+ memset(&xperms, 0, sizeof(avtab_extended_perms_t));
+
+ if (vers < POLICYDB_VERSION_AVTAB) {
+ rc = next_entry(buf32, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ items2 = le32_to_cpu(buf32[0]);
+
+ if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) {
+ ERR(fp->handle, "invalid item count");
+ return -1;
+ }
+
+ rc = next_entry(buf32, fp, sizeof(uint32_t) * items2);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+
+ items = 0;
+ val = le32_to_cpu(buf32[items++]);
+ key.source_type = (uint16_t) val;
+ if (key.source_type != val) {
+ ERR(fp->handle, "truncated source type");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_type = (uint16_t) val;
+ if (key.target_type != val) {
+ ERR(fp->handle, "truncated target type");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_class = (uint16_t) val;
+ if (key.target_class != val) {
+ ERR(fp->handle, "truncated target class");
+ return -1;
+ }
+
+ val = le32_to_cpu(buf32[items++]);
+ enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+ if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+ ERR(fp->handle, "null entry");
+ return -1;
+ }
+ if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+ ERR(fp->handle, "entry has both access "
+ "vectors and types");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+ if (val & spec_order[i]) {
+ key.specified = spec_order[i] | enabled;
+ datum.data = le32_to_cpu(buf32[items++]);
+ rc = insertf(a, &key, &datum, p);
+ if (rc)
+ return rc;
+ }
+ }
+
+ if (items != items2) {
+ ERR(fp->handle, "entry only had %d items, "
+ "expected %d", items2, items);
+ return -1;
+ }
+ return 0;
+ }
+
+ rc = next_entry(buf16, fp, sizeof(uint16_t) * 4);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ items = 0;
+ key.source_type = le16_to_cpu(buf16[items++]);
+ key.target_type = le16_to_cpu(buf16[items++]);
+ key.target_class = le16_to_cpu(buf16[items++]);
+ key.specified = le16_to_cpu(buf16[items++]);
+
+ set = 0;
+ for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
+ if (key.specified & spec_order[i])
+ set++;
+ }
+ if (!set || set > 1) {
+ ERR(fp->handle, "more than one specifier");
+ return -1;
+ }
+
+ if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+ (key.specified & AVTAB_XPERMS)) {
+ ERR(fp->handle, "policy version %u does not support extended "
+ "permissions rules and one was specified\n", vers);
+ return -1;
+ } else if (key.specified & AVTAB_XPERMS) {
+ rc = next_entry(&buf8, fp, sizeof(uint8_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ xperms.specified = buf8;
+ rc = next_entry(&buf8, fp, sizeof(uint8_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ xperms.driver = buf8;
+ rc = next_entry(buf32, fp, sizeof(uint32_t)*8);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ for (i = 0; i < ARRAY_SIZE(xperms.perms); i++)
+ xperms.perms[i] = le32_to_cpu(buf32[i]);
+ datum.xperms = &xperms;
+ } else {
+ rc = next_entry(buf32, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated entry");
+ return -1;
+ }
+ datum.data = le32_to_cpu(*buf32);
+ }
+ return insertf(a, &key, &datum, p);
+}
+
+static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d,
+ void *p __attribute__ ((unused)))
+{
+ return avtab_insert(a, k, d);
+}
+
+int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
+{
+ unsigned int i;
+ int rc;
+ uint32_t buf[1];
+ uint32_t nel;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated table");
+ goto bad;
+ }
+ nel = le32_to_cpu(buf[0]);
+ if (!nel) {
+ ERR(fp->handle, "table is empty");
+ goto bad;
+ }
+
+ rc = avtab_alloc(a, nel);
+ if (rc) {
+ ERR(fp->handle, "out of memory");
+ goto bad;
+ }
+
+ for (i = 0; i < nel; i++) {
+ rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
+ if (rc) {
+ if (rc == SEPOL_ENOMEM)
+ ERR(fp->handle, "out of memory");
+ if (rc == SEPOL_EEXIST)
+ ERR(fp->handle, "duplicate entry");
+ ERR(fp->handle, "failed on entry %d of %u", i, nel);
+ goto bad;
+ }
+ }
+
+ return 0;
+
+ bad:
+ avtab_destroy(a);
+ return -1;
+}
diff --git a/libsepol/src/boolean_internal.h b/libsepol/src/boolean_internal.h
new file mode 100644
index 0000000..aad7ade
--- /dev/null
+++ b/libsepol/src/boolean_internal.h
@@ -0,0 +1,16 @@
+#ifndef _SEPOL_BOOLEAN_INTERNAL_H_
+#define _SEPOL_BOOLEAN_INTERNAL_H_
+
+#include <sepol/boolean_record.h>
+#include <sepol/booleans.h>
+#include "dso.h"
+
+hidden_proto(sepol_bool_key_create)
+ hidden_proto(sepol_bool_key_unpack)
+ hidden_proto(sepol_bool_get_name)
+ hidden_proto(sepol_bool_set_name)
+ hidden_proto(sepol_bool_get_value)
+ hidden_proto(sepol_bool_set_value)
+ hidden_proto(sepol_bool_create)
+ hidden_proto(sepol_bool_free)
+#endif
diff --git a/libsepol/src/boolean_record.c b/libsepol/src/boolean_record.c
new file mode 100644
index 0000000..8b64413
--- /dev/null
+++ b/libsepol/src/boolean_record.c
@@ -0,0 +1,180 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "boolean_internal.h"
+#include "debug.h"
+
+struct sepol_bool {
+ /* This boolean's name */
+ char *name;
+
+ /* Its value */
+ int value;
+};
+
+struct sepol_bool_key {
+ /* This boolean's name */
+ const char *name;
+};
+
+int sepol_bool_key_create(sepol_handle_t * handle,
+ const char *name, sepol_bool_key_t ** key_ptr)
+{
+
+ sepol_bool_key_t *tmp_key =
+ (sepol_bool_key_t *) malloc(sizeof(struct sepol_bool_key));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, " "could not create boolean key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_key_create)
+
+void sepol_bool_key_unpack(const sepol_bool_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_bool_key_unpack)
+
+int sepol_bool_key_extract(sepol_handle_t * handle,
+ const sepol_bool_t * boolean,
+ sepol_bool_key_t ** key_ptr)
+{
+
+ if (sepol_bool_key_create(handle, boolean->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from boolean %s",
+ boolean->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_bool_key_free(sepol_bool_key_t * key)
+{
+ free(key);
+}
+
+int sepol_bool_compare(const sepol_bool_t * boolean,
+ const sepol_bool_key_t * key)
+{
+
+ return strcmp(boolean->name, key->name);
+}
+
+int sepol_bool_compare2(const sepol_bool_t * boolean,
+ const sepol_bool_t * boolean2)
+{
+
+ return strcmp(boolean->name, boolean2->name);
+}
+
+/* Name */
+const char *sepol_bool_get_name(const sepol_bool_t * boolean)
+{
+
+ return boolean->name;
+}
+
+hidden_def(sepol_bool_get_name)
+
+int sepol_bool_set_name(sepol_handle_t * handle,
+ sepol_bool_t * boolean, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, could not set boolean name");
+ return STATUS_ERR;
+ }
+ free(boolean->name);
+ boolean->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_set_name)
+
+/* Value */
+int sepol_bool_get_value(const sepol_bool_t * boolean)
+{
+
+ return boolean->value;
+}
+
+hidden_def(sepol_bool_get_value)
+
+void sepol_bool_set_value(sepol_bool_t * boolean, int value)
+{
+
+ boolean->value = value;
+}
+
+hidden_def(sepol_bool_set_value)
+
+/* Create */
+int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr)
+{
+
+ sepol_bool_t *boolean = (sepol_bool_t *) malloc(sizeof(sepol_bool_t));
+
+ if (!boolean) {
+ ERR(handle, "out of memory, "
+ "could not create boolean record");
+ return STATUS_ERR;
+ }
+
+ boolean->name = NULL;
+ boolean->value = 0;
+
+ *bool_ptr = boolean;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_bool_create)
+
+/* Deep copy clone */
+int sepol_bool_clone(sepol_handle_t * handle,
+ const sepol_bool_t * boolean, sepol_bool_t ** bool_ptr)
+{
+
+ sepol_bool_t *new_bool = NULL;
+
+ if (sepol_bool_create(handle, &new_bool) < 0)
+ goto err;
+
+ if (sepol_bool_set_name(handle, new_bool, boolean->name) < 0)
+ goto err;
+
+ new_bool->value = boolean->value;
+
+ *bool_ptr = new_bool;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone boolean record");
+ sepol_bool_free(new_bool);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_bool_free(sepol_bool_t * boolean)
+{
+
+ if (!boolean)
+ return;
+
+ free(boolean->name);
+ free(boolean);
+}
+
+hidden_def(sepol_bool_free)
diff --git a/libsepol/src/booleans.c b/libsepol/src/booleans.c
new file mode 100644
index 0000000..c914a28
--- /dev/null
+++ b/libsepol/src/booleans.c
@@ -0,0 +1,215 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "handle.h"
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/booleans.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include "boolean_internal.h"
+
+static int bool_update(sepol_handle_t * handle,
+ policydb_t * policydb,
+ const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+ const char *cname;
+ char *name;
+ int value;
+
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+ value = sepol_bool_get_value(data);
+
+ if (!name)
+ goto omem;
+
+ cond_bool_datum_t *datum =
+ hashtab_search(policydb->p_bools.table, name);
+ if (!datum) {
+ ERR(handle, "boolean %s no longer in policy", name);
+ goto err;
+ }
+ if (value != 0 && value != 1) {
+ ERR(handle, "illegal value %d for boolean %s", value, name);
+ goto err;
+ }
+
+ free(name);
+ datum->state = value;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(name);
+ ERR(handle, "could not update boolean %s", cname);
+ return STATUS_ERR;
+}
+
+static int bool_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ int bool_idx, sepol_bool_t ** record)
+{
+
+ const char *name = policydb->p_bool_val_to_name[bool_idx];
+ cond_bool_datum_t *booldatum = policydb->bool_val_to_struct[bool_idx];
+ int value = booldatum->state;
+
+ sepol_bool_t *tmp_record = NULL;
+
+ if (sepol_bool_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_bool_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ sepol_bool_set_value(tmp_record, value);
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert boolean %s to record", name);
+ sepol_bool_free(tmp_record);
+ return STATUS_ERR;
+}
+
+int sepol_bool_set(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_bool_key_t * key, const sepol_bool_t * data)
+{
+
+ const char *name;
+ sepol_bool_key_unpack(key, &name);
+
+ policydb_t *policydb = &p->p;
+ if (bool_update(handle, policydb, key, data) < 0)
+ goto err;
+
+ if (evaluate_conds(policydb) < 0) {
+ ERR(handle, "error while re-evaluating conditionals");
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not set boolean %s", name);
+ return STATUS_ERR;
+}
+
+int sepol_bool_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ *response = policydb->p_bools.nprim;
+
+ return STATUS_SUCCESS;
+}
+
+int sepol_bool_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+
+ const char *cname;
+ char *name = NULL;
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+
+ if (!name) {
+ ERR(handle, "out of memory, could not check "
+ "if user %s exists", cname);
+ return STATUS_ERR;
+ }
+
+ *response = (hashtab_search(policydb->p_bools.table, name) != NULL);
+ free(name);
+ return STATUS_SUCCESS;
+}
+
+int sepol_bool_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_bool_key_t * key, sepol_bool_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ cond_bool_datum_t *booldatum = NULL;
+
+ const char *cname;
+ char *name = NULL;
+ sepol_bool_key_unpack(key, &cname);
+ name = strdup(cname);
+
+ if (!name)
+ goto omem;
+
+ booldatum = hashtab_search(policydb->p_bools.table, name);
+ if (!booldatum) {
+ *response = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (bool_to_record(handle, policydb,
+ booldatum->s.value - 1, response) < 0)
+ goto err;
+
+ free(name);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not query boolean %s", cname);
+ free(name);
+ return STATUS_ERR;
+}
+
+int sepol_bool_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_bool_t * boolean,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ unsigned int nbools = policydb->p_bools.nprim;
+ sepol_bool_t *boolean = NULL;
+ unsigned int i;
+
+ /* For each boolean */
+ for (i = 0; i < nbools; i++) {
+
+ int status;
+
+ if (bool_to_record(handle, policydb, i, &boolean) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(boolean, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_bool_free(boolean);
+ boolean = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over booleans");
+ sepol_bool_free(boolean);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c
new file mode 100644
index 0000000..ea47cdd
--- /dev/null
+++ b/libsepol/src/conditional.c
@@ -0,0 +1,923 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ * Frank Mayer <mayerf@tresys.com>
+ * David Caplan <dac@tresys.com>
+ *
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/conditional.h>
+
+#include "private.h"
+
+/* move all type rules to top of t/f lists to help kernel on evaluation */
+static void cond_optimize(cond_av_list_t ** l)
+{
+ cond_av_list_t *top, *p, *cur;
+
+ top = p = cur = *l;
+
+ while (cur) {
+ if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
+ p->next = cur->next;
+ cur->next = top;
+ top = cur;
+ cur = p->next;
+ } else {
+ p = cur;
+ cur = cur->next;
+ }
+ }
+ *l = top;
+}
+
+/* reorder t/f lists for kernel */
+void cond_optimize_lists(cond_list_t * cl)
+{
+ cond_list_t *n;
+
+ for (n = cl; n != NULL; n = n->next) {
+ cond_optimize(&n->true_list);
+ cond_optimize(&n->false_list);
+ }
+}
+
+static int bool_present(unsigned int target, unsigned int bools[],
+ unsigned int num_bools)
+{
+ unsigned int i = 0;
+ int ret = 1;
+
+ if (num_bools > COND_MAX_BOOLS) {
+ return 0;
+ }
+ while (i < num_bools && target != bools[i])
+ i++;
+ if (i == num_bools)
+ ret = 0; /* got to end w/o match */
+ return ret;
+}
+
+static int same_bools(cond_node_t * a, cond_node_t * b)
+{
+ unsigned int i, x;
+
+ x = a->nbools;
+
+ /* same number of bools? */
+ if (x != b->nbools)
+ return 0;
+
+ /* make sure all the bools in a are also in b */
+ for (i = 0; i < x; i++)
+ if (!bool_present(a->bool_ids[i], b->bool_ids, x))
+ return 0;
+ return 1;
+}
+
+/*
+ * Determine if two conditional expressions are equal.
+ */
+int cond_expr_equal(cond_node_t * a, cond_node_t * b)
+{
+ cond_expr_t *cur_a, *cur_b;
+
+ if (a == NULL || b == NULL)
+ return 0;
+
+ if (a->nbools != b->nbools)
+ return 0;
+
+ /* if exprs have <= COND_MAX_BOOLS we can check the precompute values
+ * for the expressions.
+ */
+ if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
+ if (!same_bools(a, b))
+ return 0;
+ return (a->expr_pre_comp == b->expr_pre_comp);
+ }
+
+ /* for long expressions we check for exactly the same expression */
+ cur_a = a->expr;
+ cur_b = b->expr;
+ while (1) {
+ if (cur_a == NULL && cur_b == NULL)
+ return 1;
+ else if (cur_a == NULL || cur_b == NULL)
+ return 0;
+ if (cur_a->expr_type != cur_b->expr_type)
+ return 0;
+ if (cur_a->expr_type == COND_BOOL) {
+ if (cur_a->bool != cur_b->bool)
+ return 0;
+ }
+ cur_a = cur_a->next;
+ cur_b = cur_b->next;
+ }
+ return 1;
+}
+
+/* Create a new conditional node, optionally copying
+ * the conditional expression from an existing node.
+ * If node is NULL then a new node will be created
+ * with no conditional expression.
+ */
+cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
+{
+ cond_node_t *new_node;
+ unsigned int i;
+
+ new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
+ if (!new_node) {
+ return NULL;
+ }
+ memset(new_node, 0, sizeof(cond_node_t));
+
+ if (node) {
+ new_node->expr = cond_copy_expr(node->expr);
+ if (!new_node->expr) {
+ free(new_node);
+ return NULL;
+ }
+ new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
+ new_node->nbools = node->nbools;
+ for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
+ new_node->bool_ids[i] = node->bool_ids[i];
+ new_node->expr_pre_comp = node->expr_pre_comp;
+ new_node->flags = node->flags;
+ }
+
+ return new_node;
+}
+
+/* Find a conditional (the needle) within a list of existing ones (the
+ * haystack) that has a matching expression. If found, return a
+ * pointer to the existing node, setting 'was_created' to 0.
+ * Otherwise create a new one and return it, setting 'was_created' to
+ * 1. */
+cond_node_t *cond_node_find(policydb_t * p,
+ cond_node_t * needle, cond_node_t * haystack,
+ int *was_created)
+{
+ while (haystack) {
+ if (cond_expr_equal(needle, haystack)) {
+ *was_created = 0;
+ return haystack;
+ }
+ haystack = haystack->next;
+ }
+ *was_created = 1;
+
+ return cond_node_create(p, needle);
+}
+
+/* return either a pre-existing matching node or create a new node */
+cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
+ cond_node_t * cn)
+{
+ int was_created;
+ cond_node_t *result = cond_node_find(p, cn, list, &was_created);
+ if (result != NULL && was_created) {
+ /* add conditional node to policy list */
+ result->next = p->cond_list;
+ p->cond_list = result;
+ }
+ return result;
+}
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
+{
+
+ cond_expr_t *cur;
+ int s[COND_EXPR_MAXDEPTH];
+ int sp = -1;
+
+ s[0] = -1;
+
+ for (cur = expr; cur != NULL; cur = cur->next) {
+ switch (cur->expr_type) {
+ case COND_BOOL:
+ if (sp == (COND_EXPR_MAXDEPTH - 1))
+ return -1;
+ sp++;
+ s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+ break;
+ case COND_NOT:
+ if (sp < 0)
+ return -1;
+ s[sp] = !s[sp];
+ break;
+ case COND_OR:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] |= s[sp + 1];
+ break;
+ case COND_AND:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] &= s[sp + 1];
+ break;
+ case COND_XOR:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] ^= s[sp + 1];
+ break;
+ case COND_EQ:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] = (s[sp] == s[sp + 1]);
+ break;
+ case COND_NEQ:
+ if (sp < 1)
+ return -1;
+ sp--;
+ s[sp] = (s[sp] != s[sp + 1]);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return s[0];
+}
+
+cond_expr_t *cond_copy_expr(cond_expr_t * expr)
+{
+ cond_expr_t *cur, *head, *tail, *new_expr;
+ tail = head = NULL;
+ cur = expr;
+ while (cur) {
+ new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
+ if (!new_expr)
+ goto free_head;
+ memset(new_expr, 0, sizeof(cond_expr_t));
+
+ new_expr->expr_type = cur->expr_type;
+ new_expr->bool = cur->bool;
+
+ if (!head)
+ head = new_expr;
+ if (tail)
+ tail->next = new_expr;
+ tail = new_expr;
+ cur = cur->next;
+ }
+ return head;
+
+ free_head:
+ while (head) {
+ tail = head->next;
+ free(head);
+ head = tail;
+ }
+ return NULL;
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a cond_node_t and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
+{
+ int new_state;
+ cond_av_list_t *cur;
+
+ new_state = cond_evaluate_expr(p, node->expr);
+ if (new_state != node->cur_state) {
+ node->cur_state = new_state;
+ if (new_state == -1)
+ printf
+ ("expression result was undefined - disabling all rules.\n");
+ /* turn the rules on or off */
+ for (cur = node->true_list; cur != NULL; cur = cur->next) {
+ if (new_state <= 0) {
+ cur->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ cur->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+
+ for (cur = node->false_list; cur != NULL; cur = cur->next) {
+ /* -1 or 1 */
+ if (new_state) {
+ cur->node->key.specified &= ~AVTAB_ENABLED;
+ } else {
+ cur->node->key.specified |= AVTAB_ENABLED;
+ }
+ }
+ }
+ return 0;
+}
+
+/* precompute and simplify an expression if possible. If left with !expression, change
+ * to expression and switch t and f. precompute expression for expressions with limited
+ * number of bools.
+ */
+int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
+{
+ cond_expr_t *ne, *e;
+ cond_av_list_t *tmp;
+ unsigned int i, j, orig_value[COND_MAX_BOOLS];
+ int k;
+ uint32_t test = 0x0;
+ avrule_t *tmp2;
+
+ cn->nbools = 0;
+
+ memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
+ cn->expr_pre_comp = 0x0;
+
+ /* take care of !expr case */
+ ne = NULL;
+ e = cn->expr;
+
+ /* becuase it's RPN look at last element */
+ while (e->next != NULL) {
+ ne = e;
+ e = e->next;
+ }
+ if (e->expr_type == COND_NOT) {
+ if (ne) {
+ ne->next = NULL;
+ } else { /* ne should never be NULL */
+ printf
+ ("Found expr with no bools and only a ! - this should never happen.\n");
+ return -1;
+ }
+ /* swap the true and false lists */
+ tmp = cn->true_list;
+ cn->true_list = cn->false_list;
+ cn->false_list = tmp;
+ tmp2 = cn->avtrue_list;
+ cn->avtrue_list = cn->avfalse_list;
+ cn->avfalse_list = tmp2;
+
+ /* free the "not" node in the list */
+ free(e);
+ }
+
+ /* find all the bools in the expression */
+ for (e = cn->expr; e != NULL; e = e->next) {
+ switch (e->expr_type) {
+ case COND_BOOL:
+ i = 0;
+ /* see if we've already seen this bool */
+ if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) {
+ /* count em all but only record up to COND_MAX_BOOLS */
+ if (cn->nbools < COND_MAX_BOOLS)
+ cn->bool_ids[cn->nbools++] = e->bool;
+ else
+ cn->nbools++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* only precompute for exprs with <= COND_AX_BOOLS */
+ if (cn->nbools <= COND_MAX_BOOLS) {
+ /* save the default values for the bools so we can play with them */
+ for (i = 0; i < cn->nbools; i++) {
+ orig_value[i] =
+ p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
+ }
+
+ /* loop through all possible combinations of values for bools in expression */
+ for (test = 0x0; test < (0x1U << cn->nbools); test++) {
+ /* temporarily set the value for all the bools in the
+ * expression using the corr. bit in test */
+ for (j = 0; j < cn->nbools; j++) {
+ p->bool_val_to_struct[cn->bool_ids[j] -
+ 1]->state =
+ (test & (0x1 << j)) ? 1 : 0;
+ }
+ k = cond_evaluate_expr(p, cn->expr);
+ if (k == -1) {
+ printf
+ ("While testing expression, expression result "
+ "was undefined - this should never happen.\n");
+ return -1;
+ }
+ /* set the bit if expression evaluates true */
+ if (k)
+ cn->expr_pre_comp |= 0x1 << test;
+ }
+
+ /* restore bool default values */
+ for (i = 0; i < cn->nbools; i++)
+ p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
+ orig_value[i];
+ }
+ return 0;
+}
+
+int evaluate_conds(policydb_t * p)
+{
+ int ret;
+ cond_node_t *cur;
+
+ for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+ ret = evaluate_cond_node(p, cur);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int cond_policydb_init(policydb_t * p)
+{
+ p->bool_val_to_struct = NULL;
+ p->cond_list = NULL;
+ if (avtab_init(&p->te_cond_avtab))
+ return -1;
+
+ return 0;
+}
+
+void cond_av_list_destroy(cond_av_list_t * list)
+{
+ cond_av_list_t *cur, *next;
+ for (cur = list; cur != NULL; cur = next) {
+ next = cur->next;
+ /* the avtab_ptr_t node is destroy by the avtab */
+ free(cur);
+ }
+}
+
+void cond_expr_destroy(cond_expr_t * expr)
+{
+ cond_expr_t *cur_expr, *next_expr;
+
+ if (!expr)
+ return;
+
+ for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
+ next_expr = cur_expr->next;
+ free(cur_expr);
+ }
+}
+
+void cond_node_destroy(cond_node_t * node)
+{
+ if (!node)
+ return;
+
+ cond_expr_destroy(node->expr);
+ avrule_list_destroy(node->avtrue_list);
+ avrule_list_destroy(node->avfalse_list);
+ cond_av_list_destroy(node->true_list);
+ cond_av_list_destroy(node->false_list);
+}
+
+void cond_list_destroy(cond_list_t * list)
+{
+ cond_node_t *next, *cur;
+
+ if (list == NULL)
+ return;
+
+ for (cur = list; cur != NULL; cur = next) {
+ next = cur->next;
+ cond_node_destroy(cur);
+ free(cur);
+ }
+}
+
+void cond_policydb_destroy(policydb_t * p)
+{
+ if (p->bool_val_to_struct != NULL)
+ free(p->bool_val_to_struct);
+ avtab_destroy(&p->te_cond_avtab);
+ cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(policydb_t * p)
+{
+ if (p->bool_val_to_struct)
+ free(p->bool_val_to_struct);
+ p->bool_val_to_struct = (cond_bool_datum_t **)
+ malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *));
+ if (!p->bool_val_to_struct)
+ return -1;
+ return 0;
+}
+
+int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ free(datum);
+ return 0;
+}
+
+int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ cond_bool_datum_t *booldatum;
+
+ booldatum = datum;
+ p = datap;
+
+ if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
+ return -EINVAL;
+
+ p->p_bool_val_to_name[booldatum->s.value - 1] = key;
+ p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
+
+ return 0;
+}
+
+static int bool_isvalid(cond_bool_datum_t * b)
+{
+ if (!(b->state == 0 || b->state == 1))
+ return 0;
+ return 1;
+}
+
+int cond_read_bool(policydb_t * p,
+ hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ cond_bool_datum_t *booldatum;
+ uint32_t buf[3], len;
+ int rc;
+
+ booldatum = malloc(sizeof(cond_bool_datum_t));
+ if (!booldatum)
+ return -1;
+ memset(booldatum, 0, sizeof(cond_bool_datum_t));
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto err;
+
+ booldatum->s.value = le32_to_cpu(buf[0]);
+ booldatum->state = le32_to_cpu(buf[1]);
+
+ if (!bool_isvalid(booldatum))
+ goto err;
+
+ len = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto err;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto err;
+ key[len] = 0;
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+ booldatum->flags = le32_to_cpu(buf[0]);
+ }
+
+ if (hashtab_insert(h, key, booldatum))
+ goto err;
+
+ return 0;
+ err:
+ cond_destroy_bool(key, booldatum, 0);
+ return -1;
+}
+
+struct cond_insertf_data {
+ struct policydb *p;
+ cond_av_list_t *other;
+ cond_av_list_t *head;
+ cond_av_list_t *tail;
+};
+
+static int cond_insertf(avtab_t * a
+ __attribute__ ((unused)), avtab_key_t * k,
+ avtab_datum_t * d, void *ptr)
+{
+ struct cond_insertf_data *data = ptr;
+ struct policydb *p = data->p;
+ cond_av_list_t *other = data->other, *list, *cur;
+ avtab_ptr_t node_ptr;
+ uint8_t found;
+
+ /*
+ * For type rules we have to make certain there aren't any
+ * conflicting rules by searching the te_avtab and the
+ * cond_te_avtab.
+ */
+ if (k->specified & AVTAB_TYPE) {
+ if (avtab_search(&p->te_avtab, k)) {
+ printf
+ ("security: type rule already exists outside of a conditional.");
+ goto err;
+ }
+ /*
+ * If we are reading the false list other will be a pointer to
+ * the true list. We can have duplicate entries if there is only
+ * 1 other entry and it is in our true list.
+ *
+ * If we are reading the true list (other == NULL) there shouldn't
+ * be any other entries.
+ */
+ if (other) {
+ node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+ if (node_ptr) {
+ if (avtab_search_node_next
+ (node_ptr, k->specified)) {
+ printf
+ ("security: too many conflicting type rules.");
+ goto err;
+ }
+ found = 0;
+ for (cur = other; cur != NULL; cur = cur->next) {
+ if (cur->node == node_ptr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printf
+ ("security: conflicting type rules.\n");
+ goto err;
+ }
+ }
+ } else {
+ if (avtab_search(&p->te_cond_avtab, k)) {
+ printf
+ ("security: conflicting type rules when adding type rule for true.\n");
+ goto err;
+ }
+ }
+ }
+
+ node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+ if (!node_ptr) {
+ printf("security: could not insert rule.");
+ goto err;
+ }
+ node_ptr->parse_context = (void *)1;
+
+ list = malloc(sizeof(cond_av_list_t));
+ if (!list)
+ goto err;
+ memset(list, 0, sizeof(cond_av_list_t));
+
+ list->node = node_ptr;
+ if (!data->head)
+ data->head = list;
+ else
+ data->tail->next = list;
+ data->tail = list;
+ return 0;
+
+ err:
+ cond_av_list_destroy(data->head);
+ data->head = NULL;
+ return -1;
+}
+
+static int cond_read_av_list(policydb_t * p, void *fp,
+ cond_av_list_t ** ret_list, cond_av_list_t * other)
+{
+ unsigned int i;
+ int rc;
+ uint32_t buf[1], len;
+ struct cond_insertf_data data;
+
+ *ret_list = NULL;
+
+ len = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+ if (len == 0) {
+ return 0;
+ }
+
+ data.p = p;
+ data.other = other;
+ data.head = NULL;
+ data.tail = NULL;
+ for (i = 0; i < len; i++) {
+ rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
+ cond_insertf, &data);
+ if (rc)
+ return rc;
+
+ }
+
+ *ret_list = data.head;
+ return 0;
+}
+
+static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
+{
+ if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
+ printf
+ ("security: conditional expressions uses unknown operator.\n");
+ return 0;
+ }
+
+ if (expr->bool > p->p_bools.nprim) {
+ printf
+ ("security: conditional expressions uses unknown bool.\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
+{
+ uint32_t buf[2];
+ int len, i, rc;
+ cond_expr_t *expr = NULL, *last = NULL;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+
+ node->cur_state = le32_to_cpu(buf[0]);
+
+ len = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+
+ /* expr */
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto err;
+
+ expr = malloc(sizeof(cond_expr_t));
+ if (!expr) {
+ goto err;
+ }
+ memset(expr, 0, sizeof(cond_expr_t));
+
+ expr->expr_type = le32_to_cpu(buf[0]);
+ expr->bool = le32_to_cpu(buf[1]);
+
+ if (!expr_isvalid(p, expr)) {
+ free(expr);
+ goto err;
+ }
+
+ if (i == 0) {
+ node->expr = expr;
+ } else {
+ last->next = expr;
+ }
+ last = expr;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+ goto err;
+ if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
+ != 0)
+ goto err;
+ } else {
+ if (avrule_read_list(p, &node->avtrue_list, fp))
+ goto err;
+ if (avrule_read_list(p, &node->avfalse_list, fp))
+ goto err;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err;
+ node->flags = le32_to_cpu(buf[0]);
+ }
+
+ return 0;
+ err:
+ cond_node_destroy(node);
+ free(node);
+ return -1;
+}
+
+int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
+{
+ cond_node_t *node, *last = NULL;
+ uint32_t buf[1];
+ int i, len, rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+
+ rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
+ if (rc)
+ goto err;
+
+ for (i = 0; i < len; i++) {
+ node = malloc(sizeof(cond_node_t));
+ if (!node)
+ goto err;
+ memset(node, 0, sizeof(cond_node_t));
+
+ if (cond_read_node(p, node, fp) != 0)
+ goto err;
+
+ if (i == 0) {
+ *list = node;
+ } else {
+ last->next = node;
+ }
+ last = node;
+ }
+ return 0;
+ err:
+ return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result
+ */
+void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
+ struct sepol_av_decision *avd)
+{
+ avtab_ptr_t node;
+
+ if (!ctab || !key || !avd)
+ return;
+
+ for (node = avtab_search_node(ctab, key); node != NULL;
+ node = avtab_search_node_next(node, key->specified)) {
+ if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
+ avd->allowed |= node->datum.data;
+ if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
+ /* Since a '0' in an auditdeny mask represents a
+ * permission we do NOT want to audit (dontaudit), we use
+ * the '&' operand to ensure that all '0's in the mask
+ * are retained (much unlike the allow and auditallow cases).
+ */
+ avd->auditdeny &= node->datum.data;
+ if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
+ avd->auditallow |= node->datum.data;
+ }
+ return;
+}
+
+avtab_datum_t *cond_av_list_search(avtab_key_t * key,
+ cond_av_list_t * cond_list)
+{
+
+ cond_av_list_t *cur_av;
+
+ for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
+
+ if (cur_av->node->key.source_type == key->source_type &&
+ cur_av->node->key.target_type == key->target_type &&
+ cur_av->node->key.target_class == key->target_class)
+
+ return &cur_av->node->datum;
+
+ }
+ return NULL;
+
+}
diff --git a/libsepol/src/constraint.c b/libsepol/src/constraint.c
new file mode 100644
index 0000000..7154019
--- /dev/null
+++ b/libsepol/src/constraint.c
@@ -0,0 +1,47 @@
+/* Authors: Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/constraint.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask_types.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+int constraint_expr_init(constraint_expr_t * expr)
+{
+ memset(expr, 0, sizeof(*expr));
+ ebitmap_init(&expr->names);
+ if ((expr->type_names = malloc(sizeof(*expr->type_names))) == NULL) {
+ return -1;
+ }
+ type_set_init(expr->type_names);
+ return 0;
+}
+
+void constraint_expr_destroy(constraint_expr_t * expr)
+{
+ if (expr != NULL) {
+ ebitmap_destroy(&expr->names);
+ type_set_destroy(expr->type_names);
+ free(expr->type_names);
+ free(expr);
+ }
+}
diff --git a/libsepol/src/context.c b/libsepol/src/context.c
new file mode 100644
index 0000000..84dad34
--- /dev/null
+++ b/libsepol/src/context.c
@@ -0,0 +1,338 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include "context_internal.h"
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+#include "mls.h"
+
+/* ----- Compatibility ---- */
+int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+ return context_is_valid(p, c);
+}
+
+int sepol_check_context(const char *context)
+{
+
+ return sepol_context_to_sid((const sepol_security_context_t)context,
+ strlen(context) + 1, NULL);
+}
+
+/* ---- End compatibility --- */
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid. Return 0 otherwise.
+ */
+int context_is_valid(const policydb_t * p, const context_struct_t * c)
+{
+
+ role_datum_t *role;
+ user_datum_t *usrdatum;
+ ebitmap_t types, roles;
+ int ret = 1;
+
+ ebitmap_init(&types);
+ ebitmap_init(&roles);
+ if (!c->role || c->role > p->p_roles.nprim)
+ return 0;
+
+ if (!c->user || c->user > p->p_users.nprim)
+ return 0;
+
+ if (!c->type || c->type > p->p_types.nprim)
+ return 0;
+
+ if (c->role != OBJECT_R_VAL) {
+ /*
+ * Role must be authorized for the type.
+ */
+ role = p->role_val_to_struct[c->role - 1];
+ if (!ebitmap_get_bit(&role->cache, c->type - 1))
+ /* role may not be associated with type */
+ return 0;
+
+ /*
+ * User must be authorized for the role.
+ */
+ usrdatum = p->user_val_to_struct[c->user - 1];
+ if (!usrdatum)
+ return 0;
+
+ if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
+ /* user may not be associated with role */
+ return 0;
+ }
+
+ if (!mls_context_isvalid(p, c))
+ return 0;
+
+ return ret;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int context_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ char **result, size_t * result_len)
+{
+
+ char *scontext = NULL;
+ size_t scontext_len = 0;
+ char *ptr;
+
+ /* Compute the size of the context. */
+ scontext_len +=
+ strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
+ scontext_len +=
+ strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
+ scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
+ scontext_len += mls_compute_context_len(policydb, context);
+
+ /* We must null terminate the string */
+ scontext_len += 1;
+
+ /* Allocate space for the context; caller must free this space. */
+ scontext = malloc(scontext_len);
+ if (!scontext)
+ goto omem;
+ scontext[scontext_len - 1] = '\0';
+
+ /*
+ * Copy the user name, role name and type name into the context.
+ */
+ ptr = scontext;
+ sprintf(ptr, "%s:%s:%s",
+ policydb->p_user_val_to_name[context->user - 1],
+ policydb->p_role_val_to_name[context->role - 1],
+ policydb->p_type_val_to_name[context->type - 1]);
+
+ ptr +=
+ strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
+ strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
+ strlen(policydb->p_type_val_to_name[context->type - 1]);
+
+ mls_sid_to_context(policydb, context, &ptr);
+
+ *result = scontext;
+ *result_len = scontext_len;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not convert " "context to string");
+ free(scontext);
+ return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the given record
+ */
+int context_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const sepol_context_t * record)
+{
+
+ context_struct_t *scontext = NULL;
+ user_datum_t *usrdatum;
+ role_datum_t *roldatum;
+ type_datum_t *typdatum;
+
+ /* Hashtab keys are not constant - suppress warnings */
+ char *user = strdup(sepol_context_get_user(record));
+ char *role = strdup(sepol_context_get_role(record));
+ char *type = strdup(sepol_context_get_type(record));
+ const char *mls = sepol_context_get_mls(record);
+
+ scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
+ if (!user || !role || !type || !scontext) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+ context_init(scontext);
+
+ /* User */
+ usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
+ (hashtab_key_t) user);
+ if (!usrdatum) {
+ ERR(handle, "user %s is not defined", user);
+ goto err_destroy;
+ }
+ scontext->user = usrdatum->s.value;
+
+ /* Role */
+ roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
+ (hashtab_key_t) role);
+ if (!roldatum) {
+ ERR(handle, "role %s is not defined", role);
+ goto err_destroy;
+ }
+ scontext->role = roldatum->s.value;
+
+ /* Type */
+ typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
+ (hashtab_key_t) type);
+ if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
+ ERR(handle, "type %s is not defined", type);
+ goto err_destroy;
+ }
+ scontext->type = typdatum->s.value;
+
+ /* MLS */
+ if (mls && !policydb->mls) {
+ ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
+ mls);
+ goto err_destroy;
+ } else if (!mls && policydb->mls) {
+ ERR(handle, "MLS is enabled, but no MLS context found");
+ goto err_destroy;
+ }
+ if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
+ goto err_destroy;
+
+ /* Validity check */
+ if (!context_is_valid(policydb, scontext)) {
+ if (mls) {
+ ERR(handle,
+ "invalid security context: \"%s:%s:%s:%s\"",
+ user, role, type, mls);
+ } else {
+ ERR(handle,
+ "invalid security context: \"%s:%s:%s\"",
+ user, role, type);
+ }
+ goto err_destroy;
+ }
+
+ *cptr = scontext;
+ free(user);
+ free(type);
+ free(role);
+ return STATUS_SUCCESS;
+
+ err_destroy:
+ errno = EINVAL;
+ context_destroy(scontext);
+
+ err:
+ free(scontext);
+ free(user);
+ free(type);
+ free(role);
+ ERR(handle, "could not create context structure");
+ return STATUS_ERR;
+}
+
+/*
+ * Create a record from the given context structure
+ */
+int context_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ sepol_context_t ** record)
+{
+
+ sepol_context_t *tmp_record = NULL;
+ char *mls = NULL;
+
+ if (sepol_context_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_context_set_user(handle, tmp_record,
+ policydb->p_user_val_to_name[context->user -
+ 1]) < 0)
+ goto err;
+
+ if (sepol_context_set_role(handle, tmp_record,
+ policydb->p_role_val_to_name[context->role -
+ 1]) < 0)
+ goto err;
+
+ if (sepol_context_set_type(handle, tmp_record,
+ policydb->p_type_val_to_name[context->type -
+ 1]) < 0)
+ goto err;
+
+ if (policydb->mls) {
+ if (mls_to_string(handle, policydb, context, &mls) < 0)
+ goto err;
+
+ if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
+ goto err;
+ }
+
+ free(mls);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not create context record");
+ sepol_context_free(tmp_record);
+ free(mls);
+ return STATUS_ERR;
+}
+
+/*
+ * Create a context structure from the provided string.
+ */
+int context_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const char *con_str, size_t con_str_len)
+{
+
+ char *con_cpy = NULL;
+ sepol_context_t *ctx_record = NULL;
+
+ /* sepol_context_from_string expects a NULL-terminated string */
+ con_cpy = malloc(con_str_len + 1);
+ if (!con_cpy)
+ goto omem;
+ memcpy(con_cpy, con_str, con_str_len);
+ con_cpy[con_str_len] = '\0';
+
+ if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
+ goto err;
+
+ /* Now create from the data structure */
+ if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
+ goto err;
+
+ free(con_cpy);
+ sepol_context_free(ctx_record);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not create context structure");
+ free(con_cpy);
+ sepol_context_free(ctx_record);
+ return STATUS_ERR;
+}
+
+int sepol_context_check(sepol_handle_t * handle,
+ const sepol_policydb_t * policydb,
+ const sepol_context_t * context)
+{
+
+ context_struct_t *con = NULL;
+ int ret = context_from_record(handle, &policydb->p, &con, context);
+ context_destroy(con);
+ free(con);
+ return ret;
+}
diff --git a/libsepol/src/context.h b/libsepol/src/context.h
new file mode 100644
index 0000000..d25ca8a
--- /dev/null
+++ b/libsepol/src/context.h
@@ -0,0 +1,37 @@
+#ifndef _SEPOL_INTERNAL_CONTEXT_H_
+#define _SEPOL_INTERNAL_CONTEXT_H_
+
+#include <stddef.h>
+#include "context_internal.h"
+#include <sepol/policydb/context.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/handle.h>
+
+/* Create a context structure from high level representation */
+extern int context_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const sepol_context_t * data);
+
+extern int context_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ sepol_context_t ** record);
+
+/* Create a context structure from string representation */
+extern int context_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ context_struct_t ** cptr,
+ const char *con_str, size_t con_str_len);
+
+/* Check if the provided context is valid for this policy */
+extern int context_is_valid(const policydb_t * policydb,
+ const context_struct_t * context);
+
+/* Extract the context as string */
+extern int context_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * context,
+ char **result, size_t * result_len);
+
+#endif
diff --git a/libsepol/src/context_internal.h b/libsepol/src/context_internal.h
new file mode 100644
index 0000000..7987c1c
--- /dev/null
+++ b/libsepol/src/context_internal.h
@@ -0,0 +1,19 @@
+#ifndef _SEPOL_CONTEXT_INTERNAL_H_
+#define _SEPOL_CONTEXT_INTERNAL_H_
+
+#include <sepol/context_record.h>
+#include "dso.h"
+
+hidden_proto(sepol_context_clone)
+ hidden_proto(sepol_context_create)
+ hidden_proto(sepol_context_free)
+ hidden_proto(sepol_context_from_string)
+ hidden_proto(sepol_context_get_mls)
+ hidden_proto(sepol_context_get_role)
+ hidden_proto(sepol_context_get_type)
+ hidden_proto(sepol_context_get_user)
+ hidden_proto(sepol_context_set_mls)
+ hidden_proto(sepol_context_set_role)
+ hidden_proto(sepol_context_set_type)
+ hidden_proto(sepol_context_set_user)
+#endif
diff --git a/libsepol/src/context_record.c b/libsepol/src/context_record.c
new file mode 100644
index 0000000..ac2884a
--- /dev/null
+++ b/libsepol/src/context_record.c
@@ -0,0 +1,324 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_context {
+
+ /* Selinux user */
+ char *user;
+
+ /* Selinux role */
+ char *role;
+
+ /* Selinux type */
+ char *type;
+
+ /* MLS */
+ char *mls;
+};
+
+/* User */
+const char *sepol_context_get_user(const sepol_context_t * con)
+{
+
+ return con->user;
+}
+
+hidden_def(sepol_context_get_user)
+
+int sepol_context_set_user(sepol_handle_t * handle,
+ sepol_context_t * con, const char *user)
+{
+
+ char *tmp_user = strdup(user);
+ if (!tmp_user) {
+ ERR(handle, "out of memory, could not set "
+ "context user to %s", user);
+ return STATUS_ERR;
+ }
+
+ free(con->user);
+ con->user = tmp_user;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_user)
+
+/* Role */
+const char *sepol_context_get_role(const sepol_context_t * con)
+{
+
+ return con->role;
+}
+
+hidden_def(sepol_context_get_role)
+
+int sepol_context_set_role(sepol_handle_t * handle,
+ sepol_context_t * con, const char *role)
+{
+
+ char *tmp_role = strdup(role);
+ if (!tmp_role) {
+ ERR(handle, "out of memory, could not set "
+ "context role to %s", role);
+ return STATUS_ERR;
+ }
+ free(con->role);
+ con->role = tmp_role;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_role)
+
+/* Type */
+const char *sepol_context_get_type(const sepol_context_t * con)
+{
+
+ return con->type;
+}
+
+hidden_def(sepol_context_get_type)
+
+int sepol_context_set_type(sepol_handle_t * handle,
+ sepol_context_t * con, const char *type)
+{
+
+ char *tmp_type = strdup(type);
+ if (!tmp_type) {
+ ERR(handle, "out of memory, could not set "
+ "context type to %s", type);
+ return STATUS_ERR;
+ }
+ free(con->type);
+ con->type = tmp_type;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_type)
+
+/* MLS */
+const char *sepol_context_get_mls(const sepol_context_t * con)
+{
+
+ return con->mls;
+}
+
+hidden_def(sepol_context_get_mls)
+
+int sepol_context_set_mls(sepol_handle_t * handle,
+ sepol_context_t * con, const char *mls)
+{
+
+ char *tmp_mls = strdup(mls);
+ if (!tmp_mls) {
+ ERR(handle, "out of memory, could not set "
+ "MLS fields to %s", mls);
+ return STATUS_ERR;
+ }
+ free(con->mls);
+ con->mls = tmp_mls;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_set_mls)
+
+/* Create */
+int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
+{
+
+ sepol_context_t *con =
+ (sepol_context_t *) malloc(sizeof(sepol_context_t));
+
+ if (!con) {
+ ERR(handle, "out of memory, could not " "create context\n");
+ return STATUS_ERR;
+ }
+
+ con->user = NULL;
+ con->role = NULL;
+ con->type = NULL;
+ con->mls = NULL;
+ *con_ptr = con;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_context_create)
+
+/* Deep copy clone */
+int sepol_context_clone(sepol_handle_t * handle,
+ const sepol_context_t * con, sepol_context_t ** con_ptr)
+{
+
+ sepol_context_t *new_con = NULL;
+
+ if (!con) {
+ *con_ptr = NULL;
+ return 0;
+ }
+
+ if (sepol_context_create(handle, &new_con) < 0)
+ goto err;
+
+ if (!(new_con->user = strdup(con->user)))
+ goto omem;
+
+ if (!(new_con->role = strdup(con->role)))
+ goto omem;
+
+ if (!(new_con->type = strdup(con->type)))
+ goto omem;
+
+ if (con->mls && !(new_con->mls = strdup(con->mls)))
+ goto omem;
+
+ *con_ptr = new_con;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not clone context record");
+ sepol_context_free(new_con);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_context_clone)
+
+/* Destroy */
+void sepol_context_free(sepol_context_t * con)
+{
+
+ if (!con)
+ return;
+
+ free(con->user);
+ free(con->role);
+ free(con->type);
+ free(con->mls);
+ free(con);
+}
+
+hidden_def(sepol_context_free)
+
+int sepol_context_from_string(sepol_handle_t * handle,
+ const char *str, sepol_context_t ** con)
+{
+
+ char *tmp = NULL, *low, *high;
+ sepol_context_t *tmp_con = NULL;
+
+ if (!strcmp(str, "<<none>>")) {
+ *con = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (sepol_context_create(handle, &tmp_con) < 0)
+ goto err;
+
+ /* Working copy context */
+ tmp = strdup(str);
+ if (!tmp) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+ low = tmp;
+
+ /* Then, break it into its components */
+
+ /* User */
+ if (!(high = strchr(low, ':')))
+ goto mcontext;
+ else
+ *high++ = '\0';
+ if (sepol_context_set_user(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+
+ /* Role */
+ if (!(high = strchr(low, ':')))
+ goto mcontext;
+ else
+ *high++ = '\0';
+ if (sepol_context_set_role(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+
+ /* Type, and possibly MLS */
+ if (!(high = strchr(low, ':'))) {
+ if (sepol_context_set_type(handle, tmp_con, low) < 0)
+ goto err;
+ } else {
+ *high++ = '\0';
+ if (sepol_context_set_type(handle, tmp_con, low) < 0)
+ goto err;
+ low = high;
+ if (sepol_context_set_mls(handle, tmp_con, low) < 0)
+ goto err;
+ }
+
+ free(tmp);
+ *con = tmp_con;
+
+ return STATUS_SUCCESS;
+
+ mcontext:
+ errno = EINVAL;
+ ERR(handle, "malformed context \"%s\"", str);
+
+ err:
+ ERR(handle, "could not construct context from string");
+ free(tmp);
+ sepol_context_free(tmp_con);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_context_from_string)
+
+int sepol_context_to_string(sepol_handle_t * handle,
+ const sepol_context_t * con, char **str_ptr)
+{
+
+ int rc;
+ const int user_sz = strlen(con->user);
+ const int role_sz = strlen(con->role);
+ const int type_sz = strlen(con->type);
+ const int mls_sz = (con->mls) ? strlen(con->mls) : 0;
+ const int total_sz = user_sz + role_sz + type_sz +
+ mls_sz + ((con->mls) ? 3 : 2);
+
+ char *str = (char *)malloc(total_sz + 1);
+ if (!str)
+ goto omem;
+
+ if (con->mls) {
+ rc = snprintf(str, total_sz + 1, "%s:%s:%s:%s",
+ con->user, con->role, con->type, con->mls);
+ if (rc < 0 || (rc >= total_sz + 1)) {
+ ERR(handle, "print error");
+ goto err;
+ }
+ } else {
+ rc = snprintf(str, total_sz + 1, "%s:%s:%s",
+ con->user, con->role, con->type);
+ if (rc < 0 || (rc >= total_sz + 1)) {
+ ERR(handle, "print error");
+ goto err;
+ }
+ }
+
+ *str_ptr = str;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not convert context to string");
+ free(str);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/debug.c b/libsepol/src/debug.c
new file mode 100644
index 0000000..db57090
--- /dev/null
+++ b/libsepol/src/debug.c
@@ -0,0 +1,87 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "handle.h"
+#include "debug.h"
+
+/* Deprecated */
+struct sepol_handle sepol_compat_handle = {
+ .msg_callback = sepol_msg_default_handler,
+ .msg_callback_arg = NULL,
+};
+
+void sepol_debug(int on)
+{
+ sepol_compat_handle.msg_callback = (on) ?
+ sepol_msg_default_handler : NULL;
+}
+
+/* End deprecated */
+
+int sepol_msg_get_level(sepol_handle_t * handle)
+{
+ return handle->msg_level;
+}
+
+hidden_def(sepol_msg_get_level)
+
+const char *sepol_msg_get_channel(sepol_handle_t * handle)
+{
+ return handle->msg_channel;
+}
+
+hidden_def(sepol_msg_get_channel)
+
+const char *sepol_msg_get_fname(sepol_handle_t * handle)
+{
+ return handle->msg_fname;
+}
+
+hidden_def(sepol_msg_get_fname)
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+void hidden sepol_msg_default_handler(void *varg __attribute__ ((unused)),
+ sepol_handle_t * handle,
+ const char *fmt, ...)
+{
+
+ FILE *stream = NULL;
+
+ switch (sepol_msg_get_level(handle)) {
+
+ case SEPOL_MSG_ERR:
+ case SEPOL_MSG_WARN:
+ stream = stderr;
+ break;
+ case SEPOL_MSG_INFO:
+ default:
+ stream = stdout;
+ break;
+ }
+
+ fprintf(stream, "%s.%s: ",
+ sepol_msg_get_channel(handle), sepol_msg_get_fname(handle));
+
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stream, fmt, ap);
+ va_end(ap);
+
+ fprintf(stream, "\n");
+}
+
+extern void sepol_msg_set_callback(sepol_handle_t * handle,
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t *
+ handle,
+ const char *fmt, ...),
+ void *msg_callback_arg)
+{
+
+ handle->msg_callback = msg_callback;
+ handle->msg_callback_arg = msg_callback_arg;
+}
diff --git a/libsepol/src/debug.h b/libsepol/src/debug.h
new file mode 100644
index 0000000..56b397b
--- /dev/null
+++ b/libsepol/src/debug.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_INTERNAL_DEBUG_H_
+#define _SEPOL_INTERNAL_DEBUG_H_
+
+#include <stdio.h>
+#include <sepol/debug.h>
+#include "dso.h"
+#include "handle.h"
+
+#define STATUS_SUCCESS 0
+#define STATUS_ERR -1
+#define STATUS_NODATA 1
+
+/* FIXME: this needs to become a real function. Declaring variables
+ * in a macro is _evil_ as it can shadow other variables in local scope.
+ * The variable h has been renamed to _sepol_h to reduce this chance, but
+ * it is still wrong.
+ */
+#define msg_write(handle_arg, level_arg, \
+ channel_arg, func_arg, ...) do { \
+ sepol_handle_t *_sepol_h = (handle_arg) ?: &sepol_compat_handle; \
+ if (_sepol_h->msg_callback) { \
+ _sepol_h->msg_fname = func_arg; \
+ _sepol_h->msg_channel = channel_arg; \
+ _sepol_h->msg_level = level_arg; \
+ \
+ _sepol_h->msg_callback( \
+ _sepol_h->msg_callback_arg, \
+ _sepol_h, __VA_ARGS__); \
+ } \
+ } while(0)
+
+#define ERR(handle, ...) \
+ msg_write(handle, SEPOL_MSG_ERR, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#define INFO(handle, ...) \
+ msg_write(handle, SEPOL_MSG_INFO, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#define WARN(handle, ...) \
+ msg_write(handle, SEPOL_MSG_WARN, "libsepol", \
+ __FUNCTION__, __VA_ARGS__)
+
+#ifdef __GNUC__
+__attribute__ ((format(printf, 3, 4)))
+#endif
+extern void hidden sepol_msg_default_handler(void *varg,
+ sepol_handle_t * msg,
+ const char *fmt, ...);
+
+extern struct sepol_handle sepol_compat_handle;
+
+hidden_proto(sepol_msg_get_channel)
+ hidden_proto(sepol_msg_get_fname)
+ hidden_proto(sepol_msg_get_level)
+#endif
diff --git a/libsepol/src/dso.h b/libsepol/src/dso.h
new file mode 100644
index 0000000..a06e349
--- /dev/null
+++ b/libsepol/src/dso.h
@@ -0,0 +1,27 @@
+#ifndef _SEPOL_DSO_H
+#define _SEPOL_DSO_H 1
+
+#if !defined(SHARED) || defined(ANDROID)
+ #define DISABLE_SYMVER 1
+#endif
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal) \
+ extern __typeof (fct) internal; \
+ extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c
new file mode 100644
index 0000000..58f2fc4
--- /dev/null
+++ b/libsepol/src/ebitmap.c
@@ -0,0 +1,466 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the extensible bitmap type.
+ */
+
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "private.h"
+
+int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2, *new, *prev;
+
+ ebitmap_init(dst);
+
+ n1 = e1->node;
+ n2 = e2->node;
+ prev = 0;
+ while (n1 || n2) {
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new) {
+ ebitmap_destroy(dst);
+ return -ENOMEM;
+ }
+ memset(new, 0, sizeof(ebitmap_node_t));
+ if (n1 && n2 && n1->startbit == n2->startbit) {
+ new->startbit = n1->startbit;
+ new->map = n1->map | n2->map;
+ n1 = n1->next;
+ n2 = n2->next;
+ } else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
+ new->startbit = n1->startbit;
+ new->map = n1->map;
+ n1 = n1->next;
+ } else {
+ new->startbit = n2->startbit;
+ new->map = n2->map;
+ n2 = n2->next;
+ }
+
+ new->next = 0;
+ if (prev)
+ prev->next = new;
+ else
+ dst->node = new;
+ prev = new;
+ }
+
+ dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
+ return 0;
+}
+
+int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1)
+{
+ ebitmap_t tmp;
+
+ if (ebitmap_or(&tmp, dst, e1))
+ return -1;
+ ebitmap_destroy(dst);
+ dst->node = tmp.node;
+ dst->highbit = tmp.highbit;
+
+ return 0;
+}
+
+int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2)
+{
+ unsigned int i, length = min(ebitmap_length(e1), ebitmap_length(e2));
+ ebitmap_init(dst);
+ for (i=0; i < length; i++) {
+ if (ebitmap_get_bit(e1, i) && ebitmap_get_bit(e2, i)) {
+ int rc = ebitmap_set_bit(dst, i, 1);
+ if (rc < 0)
+ return rc;
+ }
+ }
+ return 0;
+}
+
+int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2)
+{
+ unsigned int i, length = max(ebitmap_length(e1), ebitmap_length(e2));
+ ebitmap_init(dst);
+ for (i=0; i < length; i++) {
+ int val = ebitmap_get_bit(e1, i) ^ ebitmap_get_bit(e2, i);
+ int rc = ebitmap_set_bit(dst, i, val);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit)
+{
+ unsigned int i;
+ ebitmap_init(dst);
+ for (i=0; i < maxbit; i++) {
+ int val = ebitmap_get_bit(e1, i);
+ int rc = ebitmap_set_bit(dst, i, !val);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit)
+{
+ ebitmap_t e3;
+ ebitmap_init(dst);
+ int rc = ebitmap_not(&e3, e2, maxbit);
+ if (rc < 0)
+ return rc;
+ rc = ebitmap_and(dst, e1, &e3);
+ ebitmap_destroy(&e3);
+ if (rc < 0)
+ return rc;
+ return 0;
+}
+
+unsigned int ebitmap_cardinality(ebitmap_t *e1)
+{
+ unsigned int i, count = 0;
+ for (i=ebitmap_startbit(e1); i < ebitmap_length(e1); i++)
+ if (ebitmap_get_bit(e1, i))
+ count++;
+ return count;
+}
+
+int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2)
+{
+ if (ebitmap_cmp(e1, e2))
+ return 0;
+ ebitmap_t tmp;
+ int rc = ebitmap_xor(&tmp, e1, e2);
+ if (rc < 0)
+ return -1;
+ int distance = ebitmap_cardinality(&tmp);
+ ebitmap_destroy(&tmp);
+ return distance;
+}
+
+int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2;
+
+ if (e1->highbit != e2->highbit)
+ return 0;
+
+ n1 = e1->node;
+ n2 = e2->node;
+ while (n1 && n2 &&
+ (n1->startbit == n2->startbit) && (n1->map == n2->map)) {
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+
+ if (n1 || n2)
+ return 0;
+
+ return 1;
+}
+
+int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src)
+{
+ ebitmap_node_t *n, *new, *prev;
+
+ ebitmap_init(dst);
+ n = src->node;
+ prev = 0;
+ while (n) {
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new) {
+ ebitmap_destroy(dst);
+ return -ENOMEM;
+ }
+ memset(new, 0, sizeof(ebitmap_node_t));
+ new->startbit = n->startbit;
+ new->map = n->map;
+ new->next = 0;
+ if (prev)
+ prev->next = new;
+ else
+ dst->node = new;
+ prev = new;
+ n = n->next;
+ }
+
+ dst->highbit = src->highbit;
+ return 0;
+}
+
+int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
+{
+ ebitmap_node_t *n1, *n2;
+
+ if (e1->highbit < e2->highbit)
+ return 0;
+
+ n1 = e1->node;
+ n2 = e2->node;
+ while (n1 && n2 && (n1->startbit <= n2->startbit)) {
+ if (n1->startbit < n2->startbit) {
+ n1 = n1->next;
+ continue;
+ }
+ if ((n1->map & n2->map) != n2->map)
+ return 0;
+
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+
+ if (n2)
+ return 0;
+
+ return 1;
+}
+
+int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2)
+{
+ ebitmap_node_t *n1 = e1->node;
+ ebitmap_node_t *n2 = e2->node;
+
+ while (n1 && n2) {
+ if (n1->startbit < n2->startbit) {
+ n1 = n1->next;
+ } else if (n2->startbit < n1->startbit) {
+ n2 = n2->next;
+ } else {
+ if (n1->map & n2->map) {
+ return 1;
+ }
+ n1 = n1->next;
+ n2 = n2->next;
+ }
+ }
+
+ return 0;
+}
+
+int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
+{
+ ebitmap_node_t *n;
+
+ if (e->highbit < bit)
+ return 0;
+
+ n = e->node;
+ while (n && (n->startbit <= bit)) {
+ if ((n->startbit + MAPSIZE) > bit) {
+ if (n->map & (MAPBIT << (bit - n->startbit)))
+ return 1;
+ else
+ return 0;
+ }
+ n = n->next;
+ }
+
+ return 0;
+}
+
+int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value)
+{
+ ebitmap_node_t *n, *prev, *new;
+ uint32_t startbit = bit & ~(MAPSIZE - 1);
+ uint32_t highbit = startbit + MAPSIZE;
+
+ if (highbit == 0) {
+ ERR(NULL, "bitmap overflow, bit 0x%x", bit);
+ return -EINVAL;
+ }
+
+ prev = 0;
+ n = e->node;
+ while (n && n->startbit <= bit) {
+ if ((n->startbit + MAPSIZE) > bit) {
+ if (value) {
+ n->map |= (MAPBIT << (bit - n->startbit));
+ } else {
+ n->map &= ~(MAPBIT << (bit - n->startbit));
+ if (!n->map) {
+ /* drop this node from the bitmap */
+
+ if (!n->next) {
+ /*
+ * this was the highest map
+ * within the bitmap
+ */
+ if (prev)
+ e->highbit =
+ prev->startbit +
+ MAPSIZE;
+ else
+ e->highbit = 0;
+ }
+ if (prev)
+ prev->next = n->next;
+ else
+ e->node = n->next;
+
+ free(n);
+ }
+ }
+ return 0;
+ }
+ prev = n;
+ n = n->next;
+ }
+
+ if (!value)
+ return 0;
+
+ new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!new)
+ return -ENOMEM;
+ memset(new, 0, sizeof(ebitmap_node_t));
+
+ new->startbit = startbit;
+ new->map = (MAPBIT << (bit - new->startbit));
+
+ if (!n) {
+ /* this node will be the highest map within the bitmap */
+ e->highbit = highbit;
+ }
+
+ if (prev) {
+ new->next = prev->next;
+ prev->next = new;
+ } else {
+ new->next = e->node;
+ e->node = new;
+ }
+
+ return 0;
+}
+
+void ebitmap_destroy(ebitmap_t * e)
+{
+ ebitmap_node_t *n, *temp;
+
+ if (!e)
+ return;
+
+ n = e->node;
+ while (n) {
+ temp = n;
+ n = n->next;
+ free(temp);
+ }
+
+ e->highbit = 0;
+ e->node = 0;
+ return;
+}
+
+int ebitmap_read(ebitmap_t * e, void *fp)
+{
+ int rc;
+ ebitmap_node_t *n, *l;
+ uint32_t buf[3], mapsize, count, i;
+ uint64_t map;
+
+ ebitmap_init(e);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto bad;
+
+ mapsize = le32_to_cpu(buf[0]);
+ e->highbit = le32_to_cpu(buf[1]);
+ count = le32_to_cpu(buf[2]);
+
+ if (mapsize != MAPSIZE) {
+ printf
+ ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n",
+ mapsize, MAPSIZE, e->highbit);
+ goto bad;
+ }
+ if (!e->highbit) {
+ e->node = NULL;
+ goto ok;
+ }
+ if (e->highbit & (MAPSIZE - 1)) {
+ printf
+ ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n",
+ e->highbit, MAPSIZE);
+ goto bad;
+ }
+ l = NULL;
+ for (i = 0; i < count; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ printf("security: ebitmap: truncated map\n");
+ goto bad;
+ }
+ n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
+ if (!n) {
+ printf("security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(n, 0, sizeof(ebitmap_node_t));
+
+ n->startbit = le32_to_cpu(buf[0]);
+
+ if (n->startbit & (MAPSIZE - 1)) {
+ printf
+ ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n",
+ n->startbit, MAPSIZE);
+ goto bad_free;
+ }
+ if (n->startbit > (e->highbit - MAPSIZE)) {
+ printf
+ ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n",
+ n->startbit, (e->highbit - MAPSIZE));
+ goto bad_free;
+ }
+ rc = next_entry(&map, fp, sizeof(uint64_t));
+ if (rc < 0) {
+ printf("security: ebitmap: truncated map\n");
+ goto bad_free;
+ }
+ n->map = le64_to_cpu(map);
+
+ if (!n->map) {
+ printf
+ ("security: ebitmap: null map in ebitmap (startbit %d)\n",
+ n->startbit);
+ goto bad_free;
+ }
+ if (l) {
+ if (n->startbit <= l->startbit) {
+ printf
+ ("security: ebitmap: start bit %d comes after start bit %d\n",
+ n->startbit, l->startbit);
+ goto bad_free;
+ }
+ l->next = n;
+ } else
+ e->node = n;
+
+ l = n;
+ }
+
+ ok:
+ rc = 0;
+ out:
+ return rc;
+ bad_free:
+ free(n);
+ bad:
+ if (!rc)
+ rc = -EINVAL;
+ ebitmap_destroy(e);
+ goto out;
+}
+
+/* FLASK */
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
new file mode 100644
index 0000000..9cb7965
--- /dev/null
+++ b/libsepol/src/expand.c
@@ -0,0 +1,3458 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "context.h"
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+#include "private.h"
+
+typedef struct expand_state {
+ int verbose;
+ uint32_t *typemap;
+ uint32_t *boolmap;
+ uint32_t *rolemap;
+ uint32_t *usermap;
+ policydb_t *base;
+ policydb_t *out;
+ sepol_handle_t *handle;
+ int expand_neverallow;
+} expand_state_t;
+
+static void expand_state_init(expand_state_t * state)
+{
+ memset(state, 0, sizeof(expand_state_t));
+}
+
+static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
+{
+ unsigned int i;
+ ebitmap_node_t *tnode;
+ ebitmap_init(dst);
+
+ ebitmap_for_each_bit(src, tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ if (!map[i])
+ continue;
+ if (ebitmap_set_bit(dst, map[i] - 1, 1))
+ return -1;
+ }
+ return 0;
+}
+
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *type, *new_type;
+ expand_state_t *state;
+
+ id = (char *)key;
+ type = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if ((type->flavor == TYPE_TYPE && !type->primary)
+ || type->flavor == TYPE_ALIAS) {
+ /* aliases are handled later */
+ return 0;
+ }
+ if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying type or attribute %s", id);
+
+ new_id = strdup(id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_type = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_type) {
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ return SEPOL_ENOMEM;
+ }
+ memset(new_type, 0, sizeof(type_datum_t));
+
+ new_type->flavor = type->flavor;
+ new_type->flags = type->flags;
+ new_type->s.value = ++state->out->p_types.nprim;
+ if (new_type->s.value > UINT16_MAX) {
+ free(new_id);
+ free(new_type);
+ ERR(state->handle, "type space overflow");
+ return -1;
+ }
+ new_type->primary = 1;
+ state->typemap[type->s.value - 1] = new_type->s.value;
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_type);
+ if (ret) {
+ free(new_id);
+ free(new_type);
+ ERR(state->handle, "hashtab overflow");
+ return -1;
+ }
+
+ if (new_type->flags & TYPE_FLAGS_PERMISSIVE)
+ if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) {
+ ERR(state->handle, "Out of memory!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int attr_convert_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id;
+ type_datum_t *type, *new_type;
+ expand_state_t *state;
+ ebitmap_t tmp_union;
+
+ id = (char *)key;
+ type = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (type->flavor != TYPE_ATTRIB)
+ return 0;
+
+ if (!is_id_enabled(id, state->base, SYM_TYPES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "converting attribute %s", id);
+
+ new_type = hashtab_search(state->out->p_types.table, id);
+ if (!new_type) {
+ ERR(state->handle, "attribute %s vanished!", id);
+ return -1;
+ }
+ if (map_ebitmap(&type->types, &tmp_union, state->typemap)) {
+ ERR(state->handle, "out of memory");
+ return -1;
+ }
+
+ /* then union tmp_union onto &new_type->types */
+ if (ebitmap_union(&new_type->types, &tmp_union)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union);
+
+ return 0;
+}
+
+static int perm_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ symtab_t *s;
+ perm_datum_t *perm, *new_perm;
+
+ id = key;
+ perm = (perm_datum_t *) datum;
+ s = (symtab_t *) data;
+
+ new_perm = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+ if (!new_perm) {
+ return -1;
+ }
+ memset(new_perm, 0, sizeof(perm_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ free(new_perm);
+ return -1;
+ }
+
+ new_perm->s.value = perm->s.value;
+ s->nprim++;
+
+ ret = hashtab_insert(s->table, new_id, (hashtab_datum_t *) new_perm);
+ if (ret) {
+ free(new_id);
+ free(new_perm);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int common_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ common_datum_t *common, *new_common;
+ expand_state_t *state;
+
+ id = (char *)key;
+ common = (common_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (state->verbose)
+ INFO(state->handle, "copying common %s", id);
+
+ new_common = (common_datum_t *) malloc(sizeof(common_datum_t));
+ if (!new_common) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_common, 0, sizeof(common_datum_t));
+ if (symtab_init(&new_common->permissions, PERM_SYMTAB_SIZE)) {
+ ERR(state->handle, "Out of memory!");
+ free(new_common);
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ /* free memory created by symtab_init first, then free new_common */
+ symtab_destroy(&new_common->permissions);
+ free(new_common);
+ return -1;
+ }
+
+ new_common->s.value = common->s.value;
+ state->out->p_commons.nprim++;
+
+ ret =
+ hashtab_insert(state->out->p_commons.table, new_id,
+ (hashtab_datum_t *) new_common);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_common);
+ free(new_id);
+ return -1;
+ }
+
+ if (hashtab_map
+ (common->permissions.table, perm_copy_callback,
+ &new_common->permissions)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int constraint_node_clone(constraint_node_t ** dst,
+ constraint_node_t * src,
+ expand_state_t * state)
+{
+ constraint_node_t *new_con = NULL, *last_new_con = NULL;
+ constraint_expr_t *new_expr = NULL;
+ *dst = NULL;
+ while (src != NULL) {
+ constraint_expr_t *expr, *expr_l = NULL;
+ new_con =
+ (constraint_node_t *) malloc(sizeof(constraint_node_t));
+ if (!new_con) {
+ goto out_of_mem;
+ }
+ memset(new_con, 0, sizeof(constraint_node_t));
+ new_con->permissions = src->permissions;
+ for (expr = src->expr; expr; expr = expr->next) {
+ if ((new_expr = calloc(1, sizeof(*new_expr))) == NULL) {
+ goto out_of_mem;
+ }
+ if (constraint_expr_init(new_expr) == -1) {
+ goto out_of_mem;
+ }
+ new_expr->expr_type = expr->expr_type;
+ new_expr->attr = expr->attr;
+ new_expr->op = expr->op;
+ if (new_expr->expr_type == CEXPR_NAMES) {
+ if (new_expr->attr & CEXPR_TYPE) {
+ /*
+ * Copy over constraint policy source types and/or
+ * attributes for sepol_compute_av_reason_buffer(3)
+ * so that utilities can analyse constraint errors.
+ */
+ if (map_ebitmap(&expr->type_names->types,
+ &new_expr->type_names->types,
+ state->typemap)) {
+ ERR(NULL, "Failed to map type_names->types");
+ goto out_of_mem;
+ }
+ /* Type sets require expansion and conversion. */
+ if (expand_convert_type_set(state->out,
+ state->
+ typemap,
+ expr->
+ type_names,
+ &new_expr->
+ names, 1)) {
+ goto out_of_mem;
+ }
+ } else if (new_expr->attr & CEXPR_ROLE) {
+ if (map_ebitmap(&expr->names, &new_expr->names, state->rolemap)) {
+ goto out_of_mem;
+ }
+ } else if (new_expr->attr & CEXPR_USER) {
+ if (map_ebitmap(&expr->names, &new_expr->names, state->usermap)) {
+ goto out_of_mem;
+ }
+ } else {
+ /* Other kinds of sets do not. */
+ if (ebitmap_cpy(&new_expr->names,
+ &expr->names)) {
+ goto out_of_mem;
+ }
+ }
+ }
+ if (expr_l) {
+ expr_l->next = new_expr;
+ } else {
+ new_con->expr = new_expr;
+ }
+ expr_l = new_expr;
+ new_expr = NULL;
+ }
+ if (last_new_con == NULL) {
+ *dst = new_con;
+ } else {
+ last_new_con->next = new_con;
+ }
+ last_new_con = new_con;
+ src = src->next;
+ }
+
+ return 0;
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ if (new_con)
+ free(new_con);
+ constraint_expr_destroy(new_expr);
+ return -1;
+}
+
+static int class_copy_default_new_object(expand_state_t *state,
+ class_datum_t *olddatum,
+ class_datum_t *newdatum)
+{
+ if (olddatum->default_user) {
+ if (newdatum->default_user && olddatum->default_user != newdatum->default_user) {
+ ERR(state->handle, "Found conflicting default user definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_user = olddatum->default_user;
+
+ }
+ if (olddatum->default_role) {
+ if (newdatum->default_role && olddatum->default_role != newdatum->default_role) {
+ ERR(state->handle, "Found conflicting default role definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_role = olddatum->default_role;
+ }
+ if (olddatum->default_type) {
+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
+ ERR(state->handle, "Found conflicting default type definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_type = olddatum->default_type;
+ }
+ if (olddatum->default_range) {
+ if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
+ ERR(state->handle, "Found conflicting default range definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_range = olddatum->default_range;
+ }
+ return 0;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ class_datum_t *class, *new_class;
+ expand_state_t *state;
+
+ id = (char *)key;
+ class = (class_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_CLASSES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying class %s", id);
+
+ new_class = (class_datum_t *) malloc(sizeof(class_datum_t));
+ if (!new_class) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_class, 0, sizeof(class_datum_t));
+ if (symtab_init(&new_class->permissions, PERM_SYMTAB_SIZE)) {
+ ERR(state->handle, "Out of memory!");
+ free(new_class);
+ return -1;
+ }
+
+ new_class->s.value = class->s.value;
+ state->out->p_classes.nprim++;
+
+ ret = class_copy_default_new_object(state, class, new_class);
+ if (ret) {
+ free(new_class);
+ return ret;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_class);
+ return -1;
+ }
+
+ ret =
+ hashtab_insert(state->out->p_classes.table, new_id,
+ (hashtab_datum_t *) new_class);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_class);
+ free(new_id);
+ return -1;
+ }
+
+ if (hashtab_map
+ (class->permissions.table, perm_copy_callback,
+ &new_class->permissions)) {
+ ERR(state->handle, "hashtab overflow");
+ return -1;
+ }
+
+ if (class->comkey) {
+ new_class->comkey = strdup(class->comkey);
+ if (!new_class->comkey) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_class->comdatum =
+ hashtab_search(state->out->p_commons.table,
+ new_class->comkey);
+ if (!new_class->comdatum) {
+ ERR(state->handle, "could not find common datum %s",
+ new_class->comkey);
+ return -1;
+ }
+ new_class->permissions.nprim +=
+ new_class->comdatum->permissions.nprim;
+ }
+
+ return 0;
+}
+
+static int constraint_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id;
+ class_datum_t *class, *new_class;
+ expand_state_t *state;
+
+ id = (char *)key;
+ class = (class_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ new_class = hashtab_search(state->out->p_classes.table, id);
+ if (!new_class) {
+ ERR(state->handle, "class %s vanished", id);
+ return -1;
+ }
+
+ /* constraints */
+ if (constraint_node_clone
+ (&new_class->constraints, class->constraints, state) == -1
+ || constraint_node_clone(&new_class->validatetrans,
+ class->validatetrans, state) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ type_datum_t *type = (type_datum_t *) datum;
+ type_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!type->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_TYPES))
+ return 0;
+
+ bounds_val = state->typemap[type->bounds - 1];
+
+ dest = hashtab_search(state->out->p_types.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "Type lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ role_datum_t *role = (role_datum_t *) datum;
+ role_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!role->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_ROLES))
+ return 0;
+
+ bounds_val = state->rolemap[role->bounds - 1];
+
+ dest = hashtab_search(state->out->p_roles.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "Role lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ user_datum_t *user = (user_datum_t *) datum;
+ user_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!user->bounds)
+ return 0;
+
+ if (!is_id_enabled((char *)key, state->base, SYM_USERS))
+ return 0;
+
+ bounds_val = state->usermap[user->bounds - 1];
+
+ dest = hashtab_search(state->out->p_users.table, (char *)key);
+ if (!dest) {
+ ERR(state->handle, "User lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be certain that
+ * the out symbol table will have the type that the alias refers. Otherwise, we
+ * won't be able to find the type value for the alias. We can't depend on the
+ * declaration ordering because of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *alias, *new_alias;
+ expand_state_t *state;
+ uint32_t prival;
+
+ id = (char *)key;
+ alias = (type_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ /* ignore regular types */
+ if (alias->flavor == TYPE_TYPE && alias->primary)
+ return 0;
+
+ /* ignore attributes */
+ if (alias->flavor == TYPE_ATTRIB)
+ return 0;
+
+ if (alias->flavor == TYPE_ALIAS)
+ prival = alias->primary;
+ else
+ prival = alias->s.value;
+
+ if (!is_id_enabled(state->base->p_type_val_to_name[prival - 1],
+ state->base, SYM_TYPES)) {
+ /* The primary type for this alias is not enabled, the alias
+ * shouldn't be either */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying alias %s", id);
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_alias = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_alias) {
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ return SEPOL_ENOMEM;
+ }
+ memset(new_alias, 0, sizeof(type_datum_t));
+ if (alias->flavor == TYPE_TYPE)
+ new_alias->s.value = state->typemap[alias->s.value - 1];
+ else if (alias->flavor == TYPE_ALIAS)
+ new_alias->s.value = state->typemap[alias->primary - 1];
+ else
+ assert(0); /* unreachable */
+
+ new_alias->flags = alias->flags;
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_alias);
+
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_alias);
+ free(new_id);
+ return -1;
+ }
+
+ state->typemap[alias->s.value - 1] = new_alias->s.value;
+
+ if (new_alias->flags & TYPE_FLAGS_PERMISSIVE)
+ if (ebitmap_set_bit(&state->out->permissive_map, new_alias->s.value, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *data)
+{
+ ebitmap_t mapped_roles;
+ role_datum_t *role = (role_datum_t *) datum;
+ expand_state_t *state = (expand_state_t *) data;
+
+ if (map_ebitmap(&role->dominates, &mapped_roles, state->rolemap))
+ return -1;
+
+ ebitmap_destroy(&role->dominates);
+
+ if (ebitmap_cpy(&role->dominates, &mapped_roles))
+ return -1;
+
+ ebitmap_destroy(&mapped_roles);
+
+ return 0;
+}
+
+/* For the role attribute in the base module, escalate its counterpart's
+ * types.types ebitmap in the out module to the counterparts of all the
+ * regular role that belongs to the current role attribute. Note, must be
+ * invoked after role_copy_callback so that state->rolemap is available.
+ */
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id, *base_reg_role_id;
+ role_datum_t *role, *new_role, *regular_role;
+ expand_state_t *state;
+ ebitmap_node_t *rnode;
+ unsigned int i;
+ ebitmap_t mapped_roles;
+
+ id = key;
+ role = (role_datum_t *)datum;
+ state = (expand_state_t *)data;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (!is_id_enabled(id, state->base, SYM_ROLES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ if (state->verbose)
+ INFO(state->handle, "fixing role attribute %s", id);
+
+ new_role =
+ (role_datum_t *)hashtab_search(state->out->p_roles.table, id);
+
+ assert(new_role != NULL && new_role->flavor == ROLE_ATTRIB);
+
+ ebitmap_init(&mapped_roles);
+ if (map_ebitmap(&role->roles, &mapped_roles, state->rolemap))
+ return -1;
+ if (ebitmap_union(&new_role->roles, &mapped_roles)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&mapped_roles);
+ return -1;
+ }
+ ebitmap_destroy(&mapped_roles);
+
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ /* take advantage of sym_val_to_name[]
+ * of the base module */
+ base_reg_role_id = state->base->p_role_val_to_name[i];
+ regular_role = (role_datum_t *)hashtab_search(
+ state->out->p_roles.table,
+ base_reg_role_id);
+ assert(regular_role != NULL &&
+ regular_role->flavor == ROLE_ROLE);
+
+ if (ebitmap_union(®ular_role->types.types,
+ &new_role->types.types)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id, *new_id;
+ role_datum_t *role;
+ role_datum_t *new_role;
+ expand_state_t *state;
+ ebitmap_t tmp_union_types;
+
+ id = key;
+ role = (role_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is always value 1 */
+ state->rolemap[role->s.value - 1] = 1;
+ return 0;
+ }
+
+ if (!is_id_enabled(id, state->base, SYM_ROLES)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying role %s", id);
+
+ new_role =
+ (role_datum_t *) hashtab_search(state->out->p_roles.table, id);
+ if (!new_role) {
+ new_role = (role_datum_t *) malloc(sizeof(role_datum_t));
+ if (!new_role) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_role, 0, sizeof(role_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_role);
+ return -1;
+ }
+
+ state->out->p_roles.nprim++;
+ new_role->flavor = role->flavor;
+ new_role->s.value = state->out->p_roles.nprim;
+ state->rolemap[role->s.value - 1] = new_role->s.value;
+ ret = hashtab_insert(state->out->p_roles.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_role);
+
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_role);
+ free(new_id);
+ return -1;
+ }
+ }
+
+ /* The dominates bitmap is going to be wrong for the moment,
+ * we'll come back later and remap them, after we are sure all
+ * the roles have been added */
+ if (ebitmap_union(&new_role->dominates, &role->dominates)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ ebitmap_init(&tmp_union_types);
+
+ /* convert types in the role datum in the global symtab */
+ if (expand_convert_type_set
+ (state->out, state->typemap, &role->types, &tmp_union_types, 1)) {
+ ebitmap_destroy(&tmp_union_types);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (ebitmap_union(&new_role->types.types, &tmp_union_types)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union_types);
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union_types);
+
+ return 0;
+}
+
+int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l,
+ policydb_t * p, sepol_handle_t * h)
+{
+ mls_semantic_cat_t *cat;
+ level_datum_t *levdatum;
+ unsigned int i;
+
+ mls_level_init(l);
+
+ if (!p->mls)
+ return 0;
+
+ /* Required not declared. */
+ if (!sl->sens)
+ return 0;
+
+ l->sens = sl->sens;
+ levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+ p->p_sens_val_to_name[l->sens - 1]);
+ if (!levdatum) {
+ ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n",
+ __func__);
+ errno = ENOENT;
+ return -1;
+ }
+ for (cat = sl->cat; cat; cat = cat->next) {
+ if (cat->low > cat->high) {
+ ERR(h, "Category range is not valid %s.%s",
+ p->p_cat_val_to_name[cat->low - 1],
+ p->p_cat_val_to_name[cat->high - 1]);
+ return -1;
+ }
+ for (i = cat->low - 1; i < cat->high; i++) {
+ if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+ ERR(h, "Category %s can not be associated with "
+ "level %s",
+ p->p_cat_val_to_name[i],
+ p->p_sens_val_to_name[l->sens - 1]);
+ return -1;
+ }
+ if (ebitmap_set_bit(&l->cat, i, 1)) {
+ ERR(h, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int mls_semantic_range_expand(mls_semantic_range_t * sr, mls_range_t * r,
+ policydb_t * p, sepol_handle_t * h)
+{
+ if (mls_semantic_level_expand(&sr->level[0], &r->level[0], p, h) < 0)
+ return -1;
+
+ if (mls_semantic_level_expand(&sr->level[1], &r->level[1], p, h) < 0) {
+ mls_semantic_level_destroy(&sr->level[0]);
+ return -1;
+ }
+
+ if (!mls_level_dom(&r->level[1], &r->level[0])) {
+ mls_range_destroy(r);
+ ERR(h, "MLS range high level does not dominate low level");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ expand_state_t *state;
+ user_datum_t *user;
+ user_datum_t *new_user;
+ char *id, *new_id;
+ ebitmap_t tmp_union;
+
+ id = key;
+ user = (user_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_USERS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying user %s", id);
+
+ new_user =
+ (user_datum_t *) hashtab_search(state->out->p_users.table, id);
+ if (!new_user) {
+ new_user = (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!new_user) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_user, 0, sizeof(user_datum_t));
+
+ state->out->p_users.nprim++;
+ new_user->s.value = state->out->p_users.nprim;
+ state->usermap[user->s.value - 1] = new_user->s.value;
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_user);
+ return -1;
+ }
+ ret = hashtab_insert(state->out->p_users.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_user);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ user_datum_destroy(new_user);
+ free(new_user);
+ free(new_id);
+ return -1;
+ }
+
+ /* expand the semantic MLS info */
+ if (mls_semantic_range_expand(&user->range,
+ &new_user->exp_range,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (mls_semantic_level_expand(&user->dfltlevel,
+ &new_user->exp_dfltlevel,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (!mls_level_between(&new_user->exp_dfltlevel,
+ &new_user->exp_range.level[0],
+ &new_user->exp_range.level[1])) {
+ ERR(state->handle, "default level not within user "
+ "range");
+ return -1;
+ }
+ } else {
+ /* require that the MLS info match */
+ mls_range_t tmp_range;
+ mls_level_t tmp_level;
+
+ if (mls_semantic_range_expand(&user->range, &tmp_range,
+ state->out, state->handle)) {
+ return -1;
+ }
+ if (mls_semantic_level_expand(&user->dfltlevel, &tmp_level,
+ state->out, state->handle)) {
+ mls_range_destroy(&tmp_range);
+ return -1;
+ }
+ if (!mls_range_eq(&new_user->exp_range, &tmp_range) ||
+ !mls_level_eq(&new_user->exp_dfltlevel, &tmp_level)) {
+ mls_range_destroy(&tmp_range);
+ mls_level_destroy(&tmp_level);
+ return -1;
+ }
+ mls_range_destroy(&tmp_range);
+ mls_level_destroy(&tmp_level);
+ }
+
+ ebitmap_init(&tmp_union);
+
+ /* get global roles for this user */
+ if (role_set_expand(&user->roles, &tmp_union, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union);
+ return -1;
+ }
+
+ if (ebitmap_union(&new_user->roles.roles, &tmp_union)) {
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp_union);
+ return -1;
+ }
+ ebitmap_destroy(&tmp_union);
+
+ return 0;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ expand_state_t *state;
+ cond_bool_datum_t *bool, *new_bool;
+ char *id, *new_id;
+
+ id = key;
+ bool = (cond_bool_datum_t *) datum;
+ state = (expand_state_t *) data;
+
+ if (!is_id_enabled(id, state->base, SYM_BOOLS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (bool->flags & COND_BOOL_FLAGS_TUNABLE) {
+ /* Skip tunables */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying boolean %s", id);
+
+ new_bool = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t));
+ if (!new_bool) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ ERR(state->handle, "Out of memory!");
+ free(new_bool);
+ return -1;
+ }
+
+ state->out->p_bools.nprim++;
+ new_bool->s.value = state->out->p_bools.nprim;
+
+ ret = hashtab_insert(state->out->p_bools.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_bool);
+ if (ret) {
+ ERR(state->handle, "hashtab overflow");
+ free(new_bool);
+ free(new_id);
+ return -1;
+ }
+
+ state->boolmap[bool->s.value - 1] = new_bool->s.value;
+
+ new_bool->state = bool->state;
+ new_bool->flags = bool->flags;
+
+ return 0;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ level_datum_t *level = (level_datum_t *) datum, *new_level = NULL;
+ char *id = (char *)key, *new_id = NULL;
+
+ if (!is_id_enabled(id, state->base, SYM_LEVELS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying sensitivity level %s", id);
+
+ new_level = (level_datum_t *) malloc(sizeof(level_datum_t));
+ if (!new_level)
+ goto out_of_mem;
+ level_datum_init(new_level);
+ new_level->level = (mls_level_t *) malloc(sizeof(mls_level_t));
+ if (!new_level->level)
+ goto out_of_mem;
+ mls_level_init(new_level->level);
+ new_id = strdup(id);
+ if (!new_id)
+ goto out_of_mem;
+
+ if (mls_level_cpy(new_level->level, level->level)) {
+ goto out_of_mem;
+ }
+ new_level->isalias = level->isalias;
+ state->out->p_levels.nprim++;
+
+ if (hashtab_insert(state->out->p_levels.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_level)) {
+ goto out_of_mem;
+ }
+ return 0;
+
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ if (new_level != NULL && new_level->level != NULL) {
+ mls_level_destroy(new_level->level);
+ free(new_level->level);
+ }
+ level_datum_destroy(new_level);
+ free(new_level);
+ free(new_id);
+ return -1;
+}
+
+static int cats_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ expand_state_t *state = (expand_state_t *) data;
+ cat_datum_t *cat = (cat_datum_t *) datum, *new_cat = NULL;
+ char *id = (char *)key, *new_id = NULL;
+
+ if (!is_id_enabled(id, state->base, SYM_CATS)) {
+ /* identifier's scope is not enabled */
+ return 0;
+ }
+
+ if (state->verbose)
+ INFO(state->handle, "copying category attribute %s", id);
+
+ new_cat = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+ if (!new_cat)
+ goto out_of_mem;
+ cat_datum_init(new_cat);
+ new_id = strdup(id);
+ if (!new_id)
+ goto out_of_mem;
+
+ new_cat->s.value = cat->s.value;
+ new_cat->isalias = cat->isalias;
+ state->out->p_cats.nprim++;
+ if (hashtab_insert(state->out->p_cats.table,
+ (hashtab_key_t) new_id, (hashtab_datum_t) new_cat)) {
+ goto out_of_mem;
+ }
+
+ return 0;
+
+ out_of_mem:
+ ERR(state->handle, "Out of memory!");
+ cat_datum_destroy(new_cat);
+ free(new_cat);
+ free(new_id);
+ return -1;
+}
+
+static int copy_role_allows(expand_state_t * state, role_allow_rule_t * rules)
+{
+ unsigned int i, j;
+ role_allow_t *cur_allow, *n, *l;
+ role_allow_rule_t *cur;
+ ebitmap_t roles, new_roles;
+ ebitmap_node_t *snode, *tnode;
+
+ /* start at the end of the list */
+ for (l = state->out->role_allow; l && l->next; l = l->next) ;
+
+ cur = rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&new_roles);
+
+ if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ ebitmap_for_each_bit(&roles, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&new_roles, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ /* check for duplicates */
+ cur_allow = state->out->role_allow;
+ while (cur_allow) {
+ if ((cur_allow->role == i + 1) &&
+ (cur_allow->new_role == j + 1))
+ break;
+ cur_allow = cur_allow->next;
+ }
+ if (cur_allow)
+ continue;
+ n = (role_allow_t *)
+ malloc(sizeof(role_allow_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_allow_t));
+ n->role = i + 1;
+ n->new_role = j + 1;
+ if (l) {
+ l->next = n;
+ } else {
+ state->out->role_allow = n;
+ }
+ l = n;
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&new_roles);
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
+{
+ unsigned int i, j, k;
+ role_trans_t *n, *l, *cur_trans;
+ role_trans_rule_t *cur;
+ ebitmap_t roles, types;
+ ebitmap_node_t *rnode, *tnode, *cnode;
+
+ /* start at the end of the list */
+ for (l = state->out->role_tr; l && l->next; l = l->next) ;
+
+ cur = rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&types);
+
+ if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (expand_convert_type_set
+ (state->out, state->typemap, &cur->types, &types, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ ebitmap_for_each_bit(&roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
+ continue;
+ ebitmap_for_each_bit(&types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ ebitmap_for_each_bit(&cur->classes, cnode, k) {
+ if (!ebitmap_node_get_bit(cnode, k))
+ continue;
+
+ cur_trans = state->out->role_tr;
+ while (cur_trans) {
+ unsigned int mapped_role;
+
+ mapped_role = state->rolemap[cur->new_role - 1];
+
+ if ((cur_trans->role ==
+ i + 1) &&
+ (cur_trans->type ==
+ j + 1) &&
+ (cur_trans->tclass ==
+ k + 1)) {
+ if (cur_trans->new_role == mapped_role) {
+ break;
+ } else {
+ ERR(state->handle,
+ "Conflicting role trans rule %s %s : %s { %s vs %s }",
+ state->out->p_role_val_to_name[i],
+ state->out->p_type_val_to_name[j],
+ state->out->p_class_val_to_name[k],
+ state->out->p_role_val_to_name[mapped_role - 1],
+ state->out->p_role_val_to_name[cur_trans->new_role - 1]);
+ return -1;
+ }
+ }
+ cur_trans = cur_trans->next;
+ }
+ if (cur_trans)
+ continue;
+
+ n = (role_trans_t *)
+ malloc(sizeof(role_trans_t));
+ if (!n) {
+ ERR(state->handle,
+ "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_trans_t));
+ n->role = i + 1;
+ n->type = j + 1;
+ n->tclass = k + 1;
+ n->new_role = state->rolemap
+ [cur->new_role - 1];
+ if (l)
+ l->next = n;
+ else
+ state->out->role_tr = n;
+
+ l = n;
+ }
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&types);
+
+ cur = cur->next;
+ }
+ return 0;
+}
+
+static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules)
+{
+ unsigned int i, j;
+ filename_trans_t *new_trans, *cur_trans;
+ filename_trans_rule_t *cur_rule;
+ ebitmap_t stypes, ttypes;
+ ebitmap_node_t *snode, *tnode;
+
+ cur_rule = rules;
+ while (cur_rule) {
+ uint32_t mapped_otype;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set(state->out, state->typemap,
+ &cur_rule->stypes, &stypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ if (expand_convert_type_set(state->out, state->typemap,
+ &cur_rule->ttypes, &ttypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ mapped_otype = state->typemap[cur_rule->otype - 1];
+
+ ebitmap_for_each_bit(&stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(&ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+
+ cur_trans = state->out->filename_trans;
+ while (cur_trans) {
+ if ((cur_trans->stype == i + 1) &&
+ (cur_trans->ttype == j + 1) &&
+ (cur_trans->tclass == cur_rule->tclass) &&
+ (!strcmp(cur_trans->name, cur_rule->name))) {
+ /* duplicate rule, who cares */
+ if (cur_trans->otype == mapped_otype)
+ break;
+
+ ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s",
+ state->out->p_type_val_to_name[i],
+ state->out->p_type_val_to_name[j],
+ state->out->p_class_val_to_name[cur_trans->tclass - 1],
+ cur_trans->name,
+ state->out->p_type_val_to_name[cur_trans->otype - 1],
+ state->out->p_type_val_to_name[mapped_otype - 1]);
+
+ return -1;
+ }
+ cur_trans = cur_trans->next;
+ }
+ /* duplicate rule, who cares */
+ if (cur_trans)
+ continue;
+
+ new_trans = malloc(sizeof(*new_trans));
+ if (!new_trans) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(new_trans, 0, sizeof(*new_trans));
+ new_trans->next = state->out->filename_trans;
+ state->out->filename_trans = new_trans;
+
+ new_trans->name = strdup(cur_rule->name);
+ if (!new_trans->name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ new_trans->stype = i + 1;
+ new_trans->ttype = j + 1;
+ new_trans->tclass = cur_rule->tclass;
+ new_trans->otype = mapped_otype;
+ }
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+
+ cur_rule = cur_rule->next;
+ }
+ return 0;
+}
+
+static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass,
+ mls_semantic_range_t * trange,
+ expand_state_t * state)
+{
+ range_trans_t *rt, *check_rt = state->out->range_tr;
+ mls_range_t exp_range;
+ int rc = -1;
+
+ if (mls_semantic_range_expand(trange, &exp_range, state->out,
+ state->handle))
+ goto out;
+
+ /* check for duplicates/conflicts */
+ while (check_rt) {
+ if ((check_rt->source_type == stype) &&
+ (check_rt->target_type == ttype) &&
+ (check_rt->target_class == tclass)) {
+ if (mls_range_eq(&check_rt->target_range, &exp_range)) {
+ /* duplicate */
+ break;
+ } else {
+ /* conflict */
+ ERR(state->handle,
+ "Conflicting range trans rule %s %s : %s",
+ state->out->p_type_val_to_name[stype - 1],
+ state->out->p_type_val_to_name[ttype - 1],
+ state->out->p_class_val_to_name[tclass -
+ 1]);
+ goto out;
+ }
+ }
+ check_rt = check_rt->next;
+ }
+ if (check_rt) {
+ /* this is a dup - skip */
+ rc = 0;
+ goto out;
+ }
+
+ rt = (range_trans_t *) calloc(1, sizeof(range_trans_t));
+ if (!rt) {
+ ERR(state->handle, "Out of memory!");
+ goto out;
+ }
+
+ rt->next = state->out->range_tr;
+ state->out->range_tr = rt;
+
+ rt->source_type = stype;
+ rt->target_type = ttype;
+ rt->target_class = tclass;
+ if (mls_range_cpy(&rt->target_range, &exp_range)) {
+ ERR(state->handle, "Out of memory!");
+ goto out;
+ }
+
+ rc = 0;
+
+ out:
+ mls_range_destroy(&exp_range);
+ return rc;
+}
+
+static int expand_range_trans(expand_state_t * state,
+ range_trans_rule_t * rules)
+{
+ unsigned int i, j, k;
+ range_trans_rule_t *rule;
+
+ ebitmap_t stypes, ttypes;
+ ebitmap_node_t *snode, *tnode, *cnode;
+
+ if (state->verbose)
+ INFO(state->handle, "expanding range transitions");
+
+ for (rule = rules; rule; rule = rule->next) {
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ /* expand the type sets */
+ if (expand_convert_type_set(state->out, state->typemap,
+ &rule->stypes, &stypes, 1)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (expand_convert_type_set(state->out, state->typemap,
+ &rule->ttypes, &ttypes, 1)) {
+ ebitmap_destroy(&stypes);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* loop on source type */
+ ebitmap_for_each_bit(&stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ /* loop on target type */
+ ebitmap_for_each_bit(&ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ /* loop on target class */
+ ebitmap_for_each_bit(&rule->tclasses, cnode, k) {
+ if (!ebitmap_node_get_bit(cnode, k))
+ continue;
+
+ if (exp_rangetr_helper(i + 1,
+ j + 1,
+ k + 1,
+ &rule->trange,
+ state)) {
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return -1;
+ }
+ }
+ }
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ }
+
+ return 0;
+}
+
+/* Search for an AV tab node within a hash table with the given key.
+ * If the node does not exist, create it and return it; otherwise
+ * return the pre-existing one.
+*/
+static avtab_ptr_t find_avtab_node(sepol_handle_t * handle,
+ avtab_t * avtab, avtab_key_t * key,
+ cond_av_list_t ** cond,
+ av_extended_perms_t *xperms)
+{
+ avtab_ptr_t node;
+ avtab_datum_t avdatum;
+ cond_av_list_t *nl;
+ int match = 0;
+
+ /* AVTAB_XPERMS entries are not necessarily unique */
+ if (key->specified & AVTAB_XPERMS) {
+ node = avtab_search_node(avtab, key);
+ while (node) {
+ if ((node->datum.xperms->specified == xperms->specified) &&
+ (node->datum.xperms->driver == xperms->driver)) {
+ match = 1;
+ break;
+ }
+ node = avtab_search_node_next(node, key->specified);
+ }
+ if (!match)
+ node = NULL;
+ } else {
+ node = avtab_search_node(avtab, key);
+ }
+
+ /* If this is for conditional policies, keep searching in case
+ the node is part of my conditional avtab. */
+ if (cond) {
+ while (node) {
+ if (node->parse_context == cond)
+ break;
+ node = avtab_search_node_next(node, key->specified);
+ }
+ }
+
+ if (!node) {
+ memset(&avdatum, 0, sizeof avdatum);
+ /* this is used to get the node - insertion is actually unique */
+ node = avtab_insert_nonunique(avtab, key, &avdatum);
+ if (!node) {
+ ERR(handle, "hash table overflow");
+ return NULL;
+ }
+ if (cond) {
+ node->parse_context = cond;
+ nl = (cond_av_list_t *) malloc(sizeof(cond_av_list_t));
+ if (!nl) {
+ ERR(handle, "Memory error");
+ return NULL;
+ }
+ memset(nl, 0, sizeof(cond_av_list_t));
+ nl->node = node;
+ nl->next = *cond;
+ *cond = nl;
+ }
+ }
+
+ return node;
+}
+
+#define EXPAND_RULE_SUCCESS 1
+#define EXPAND_RULE_CONFLICT 0
+#define EXPAND_RULE_ERROR -1
+
+static int expand_terule_helper(sepol_handle_t * handle,
+ policydb_t * p, uint32_t * typemap,
+ uint32_t specified, cond_av_list_t ** cond,
+ cond_av_list_t ** other, uint32_t stype,
+ uint32_t ttype, class_perm_node_t * perms,
+ avtab_t * avtab, int enabled)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ int conflict;
+ uint32_t oldtype = 0, spec = 0;
+
+ if (specified & AVRULE_TRANSITION) {
+ spec = AVTAB_TRANSITION;
+ } else if (specified & AVRULE_MEMBER) {
+ spec = AVTAB_MEMBER;
+ } else if (specified & AVRULE_CHANGE) {
+ spec = AVTAB_CHANGE;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ uint32_t remapped_data =
+ typemap ? typemap[cur->data - 1] : cur->data;
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->tclass;
+ avkey.specified = spec;
+
+ conflict = 0;
+ /* check to see if the expanded TE already exists --
+ * either in the global scope or in another
+ * conditional AV tab */
+ node = avtab_search_node(&p->te_avtab, &avkey);
+ if (node) {
+ conflict = 1;
+ } else {
+ node = avtab_search_node(&p->te_cond_avtab, &avkey);
+ if (node && node->parse_context != other) {
+ conflict = 2;
+ }
+ }
+
+ if (conflict) {
+ avdatump = &node->datum;
+ if (specified & AVRULE_TRANSITION) {
+ oldtype = avdatump->data;
+ } else if (specified & AVRULE_MEMBER) {
+ oldtype = avdatump->data;
+ } else if (specified & AVRULE_CHANGE) {
+ oldtype = avdatump->data;
+ }
+
+ if (oldtype == remapped_data) {
+ /* if the duplicate is inside the same scope (eg., unconditional
+ * or in same conditional then ignore it */
+ if ((conflict == 1 && cond == NULL)
+ || node->parse_context == cond)
+ return EXPAND_RULE_SUCCESS;
+ ERR(handle, "duplicate TE rule for %s %s:%s %s",
+ p->p_type_val_to_name[avkey.source_type -
+ 1],
+ p->p_type_val_to_name[avkey.target_type -
+ 1],
+ p->p_class_val_to_name[avkey.target_class -
+ 1],
+ p->p_type_val_to_name[oldtype - 1]);
+ return EXPAND_RULE_CONFLICT;
+ }
+ ERR(handle,
+ "conflicting TE rule for (%s, %s:%s): old was %s, new is %s",
+ p->p_type_val_to_name[avkey.source_type - 1],
+ p->p_type_val_to_name[avkey.target_type - 1],
+ p->p_class_val_to_name[avkey.target_class - 1],
+ p->p_type_val_to_name[oldtype - 1],
+ p->p_type_val_to_name[remapped_data - 1]);
+ return EXPAND_RULE_CONFLICT;
+ }
+
+ node = find_avtab_node(handle, avtab, &avkey, cond, NULL);
+ if (!node)
+ return -1;
+ if (enabled) {
+ node->key.specified |= AVTAB_ENABLED;
+ } else {
+ node->key.specified &= ~AVTAB_ENABLED;
+ }
+
+ avdatump = &node->datum;
+ if (specified & AVRULE_TRANSITION) {
+ avdatump->data = remapped_data;
+ } else if (specified & AVRULE_MEMBER) {
+ avdatump->data = remapped_data;
+ } else if (specified & AVRULE_CHANGE) {
+ avdatump->data = remapped_data;
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+
+ return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_avrule_helper(sepol_handle_t * handle,
+ uint32_t specified,
+ cond_av_list_t ** cond,
+ uint32_t stype, uint32_t ttype,
+ class_perm_node_t * perms, avtab_t * avtab,
+ int enabled, av_extended_perms_t *extended_perms)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_extended_perms_t *xperms;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ uint32_t spec = 0;
+ unsigned int i;
+
+ if (specified & AVRULE_ALLOWED) {
+ spec = AVTAB_ALLOWED;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ spec = AVTAB_AUDITALLOW;
+ } else if (specified & AVRULE_AUDITDENY) {
+ spec = AVTAB_AUDITDENY;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ if (handle && handle->disable_dontaudit)
+ return EXPAND_RULE_SUCCESS;
+ spec = AVTAB_AUDITDENY;
+ } else if (specified & AVRULE_NEVERALLOW) {
+ spec = AVTAB_NEVERALLOW;
+ } else if (specified & AVRULE_XPERMS_ALLOWED) {
+ spec = AVTAB_XPERMS_ALLOWED;
+ } else if (specified & AVRULE_XPERMS_AUDITALLOW) {
+ spec = AVTAB_XPERMS_AUDITALLOW;
+ } else if (specified & AVRULE_XPERMS_DONTAUDIT) {
+ if (handle && handle->disable_dontaudit)
+ return EXPAND_RULE_SUCCESS;
+ spec = AVTAB_XPERMS_DONTAUDIT;
+ } else if (specified & AVRULE_XPERMS_NEVERALLOW) {
+ spec = AVTAB_XPERMS_NEVERALLOW;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->tclass;
+ avkey.specified = spec;
+
+ node = find_avtab_node(handle, avtab, &avkey, cond, extended_perms);
+ if (!node)
+ return EXPAND_RULE_ERROR;
+ if (enabled) {
+ node->key.specified |= AVTAB_ENABLED;
+ } else {
+ node->key.specified &= ~AVTAB_ENABLED;
+ }
+
+ avdatump = &node->datum;
+ if (specified & AVRULE_ALLOWED) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_NEVERALLOW) {
+ avdatump->data |= cur->data;
+ } else if (specified & AVRULE_AUDITDENY) {
+ /* Since a '0' in an auditdeny mask represents
+ * a permission we do NOT want to audit
+ * (dontaudit), we use the '&' operand to
+ * ensure that all '0's in the mask are
+ * retained (much unlike the allow and
+ * auditallow cases).
+ */
+ avdatump->data &= cur->data;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ if (avdatump->data)
+ avdatump->data &= ~cur->data;
+ else
+ avdatump->data = ~cur->data;
+ } else if (specified & AVRULE_XPERMS) {
+ if (!avdatump->xperms) {
+ xperms = (avtab_extended_perms_t *)
+ calloc(1, sizeof(avtab_extended_perms_t));
+ if (!xperms) {
+ ERR(handle, "Out of memory!");
+ return -1;
+ }
+ node->datum.xperms = xperms;
+ }
+ node->datum.xperms->specified = extended_perms->specified;
+ node->datum.xperms->driver = extended_perms->driver;
+
+ for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+ node->datum.xperms->perms[i] |= extended_perms->perms[i];
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+ return EXPAND_RULE_SUCCESS;
+}
+
+static int expand_rule_helper(sepol_handle_t * handle,
+ policydb_t * p, uint32_t * typemap,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other,
+ int enabled,
+ ebitmap_t * stypes, ebitmap_t * ttypes)
+{
+ unsigned int i, j;
+ int retval;
+ ebitmap_node_t *snode, *tnode;
+
+ ebitmap_for_each_bit(stypes, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ if (source_rule->flags & RULE_SELF) {
+ if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
+ retval = expand_avrule_helper(handle, source_rule->specified,
+ cond, i, i, source_rule->perms,
+ dest_avtab, enabled, source_rule->xperms);
+ if (retval != EXPAND_RULE_SUCCESS)
+ return retval;
+ } else {
+ retval = expand_terule_helper(handle, p, typemap,
+ source_rule->specified, cond,
+ other, i, i, source_rule->perms,
+ dest_avtab, enabled);
+ if (retval != EXPAND_RULE_SUCCESS)
+ return retval;
+ }
+ }
+ ebitmap_for_each_bit(ttypes, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
+ retval = expand_avrule_helper(handle, source_rule->specified,
+ cond, i, j, source_rule->perms,
+ dest_avtab, enabled, source_rule->xperms);
+ if (retval != EXPAND_RULE_SUCCESS)
+ return retval;
+ } else {
+ retval = expand_terule_helper(handle, p, typemap,
+ source_rule->specified, cond,
+ other, i, j, source_rule->perms,
+ dest_avtab, enabled);
+ if (retval != EXPAND_RULE_SUCCESS)
+ return retval;
+ }
+ }
+ }
+
+ return EXPAND_RULE_SUCCESS;
+}
+
+/*
+ * Expand a rule into a given avtab - checking for conflicting type
+ * rules in the destination policy. Return EXPAND_RULE_SUCCESS on
+ * success, EXPAND_RULE_CONFLICT if the rule conflicts with something
+ * (and hence was not added), or EXPAND_RULE_ERROR on error.
+ */
+static int convert_and_expand_rule(sepol_handle_t * handle,
+ policydb_t * dest_pol, uint32_t * typemap,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond,
+ cond_av_list_t ** other, int enabled,
+ int do_neverallow)
+{
+ int retval;
+ ebitmap_t stypes, ttypes;
+ unsigned char alwaysexpand;
+
+ if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW)
+ return EXPAND_RULE_SUCCESS;
+ if (!do_neverallow && source_rule->specified & AVRULE_XPERMS_NEVERALLOW)
+ return EXPAND_RULE_SUCCESS;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ /* Force expansion for type rules and for self rules. */
+ alwaysexpand = ((source_rule->specified & AVRULE_TYPE) ||
+ (source_rule->flags & RULE_SELF));
+
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->stypes, &stypes, alwaysexpand))
+ return EXPAND_RULE_ERROR;
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->ttypes, &ttypes, alwaysexpand))
+ return EXPAND_RULE_ERROR;
+
+ retval = expand_rule_helper(handle, dest_pol, typemap,
+ source_rule, dest_avtab,
+ cond, other, enabled, &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+static int cond_avrule_list_copy(policydb_t * dest_pol, avrule_t * source_rules,
+ avtab_t * dest_avtab, cond_av_list_t ** list,
+ cond_av_list_t ** other, uint32_t * typemap,
+ int enabled, expand_state_t * state)
+{
+ avrule_t *cur;
+
+ cur = source_rules;
+ while (cur) {
+ if (convert_and_expand_rule(state->handle, dest_pol,
+ typemap, cur, dest_avtab,
+ list, other, enabled,
+ 0) != EXPAND_RULE_SUCCESS) {
+ return -1;
+ }
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static int cond_node_map_bools(expand_state_t * state, cond_node_t * cn)
+{
+ cond_expr_t *cur;
+ unsigned int i;
+
+ cur = cn->expr;
+ while (cur) {
+ if (cur->bool)
+ cur->bool = state->boolmap[cur->bool - 1];
+ cur = cur->next;
+ }
+
+ for (i = 0; i < min(cn->nbools, COND_MAX_BOOLS); i++)
+ cn->bool_ids[i] = state->boolmap[cn->bool_ids[i] - 1];
+
+ if (cond_normalize_expr(state->out, cn)) {
+ ERR(state->handle, "Error while normalizing conditional");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* copy the nodes in *reverse* order -- the result is that the last
+ * given conditional appears first in the policy, so as to match the
+ * behavior of the upstream compiler */
+static int cond_node_copy(expand_state_t * state, cond_node_t * cn)
+{
+ cond_node_t *new_cond, *tmp;
+
+ if (cn == NULL) {
+ return 0;
+ }
+ if (cond_node_copy(state, cn->next)) {
+ return -1;
+ }
+
+ /* If current cond_node_t is of tunable, its effective branch
+ * has been appended to its home decl->avrules list during link
+ * and now we should just skip it. */
+ if (cn->flags & COND_NODE_FLAGS_TUNABLE)
+ return 0;
+
+ if (cond_normalize_expr(state->base, cn)) {
+ ERR(state->handle, "Error while normalizing conditional");
+ return -1;
+ }
+
+ /* create a new temporary conditional node with the booleans
+ * mapped */
+ tmp = cond_node_create(state->base, cn);
+ if (!tmp) {
+ ERR(state->handle, "Out of memory");
+ return -1;
+ }
+
+ if (cond_node_map_bools(state, tmp)) {
+ cond_node_destroy(tmp);
+ free(tmp);
+ ERR(state->handle, "Error mapping booleans");
+ return -1;
+ }
+
+ new_cond = cond_node_search(state->out, state->out->cond_list, tmp);
+ if (!new_cond) {
+ cond_node_destroy(tmp);
+ free(tmp);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ cond_node_destroy(tmp);
+ free(tmp);
+
+ if (cond_avrule_list_copy
+ (state->out, cn->avtrue_list, &state->out->te_cond_avtab,
+ &new_cond->true_list, &new_cond->false_list, state->typemap,
+ new_cond->cur_state, state))
+ return -1;
+ if (cond_avrule_list_copy
+ (state->out, cn->avfalse_list, &state->out->te_cond_avtab,
+ &new_cond->false_list, &new_cond->true_list, state->typemap,
+ !new_cond->cur_state, state))
+ return -1;
+
+ return 0;
+}
+
+static int context_copy(context_struct_t * dst, context_struct_t * src,
+ expand_state_t * state)
+{
+ dst->user = state->usermap[src->user - 1];
+ dst->role = state->rolemap[src->role - 1];
+ dst->type = state->typemap[src->type - 1];
+ return mls_context_cpy(dst, src);
+}
+
+static int ocontext_copy_xen(expand_state_t *state)
+{
+ unsigned int i;
+ ocontext_t *c, *n, *l;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ l = NULL;
+ for (c = state->base->ocontexts[i]; c; c = c->next) {
+ n = malloc(sizeof(ocontext_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(ocontext_t));
+ if (l)
+ l->next = n;
+ else
+ state->out->ocontexts[i] = n;
+ l = n;
+ switch (i) {
+ case OCON_XEN_ISID:
+ if (c->context[0].user == 0) {
+ ERR(state->handle,
+ "Missing context for %s initial sid",
+ c->u.name);
+ return -1;
+ }
+ n->sid[0] = c->sid[0];
+ break;
+ case OCON_XEN_PIRQ:
+ n->u.pirq = c->u.pirq;
+ break;
+ case OCON_XEN_IOPORT:
+ n->u.ioport.low_ioport = c->u.ioport.low_ioport;
+ n->u.ioport.high_ioport =
+ c->u.ioport.high_ioport;
+ break;
+ case OCON_XEN_IOMEM:
+ n->u.iomem.low_iomem = c->u.iomem.low_iomem;
+ n->u.iomem.high_iomem = c->u.iomem.high_iomem;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ n->u.device = c->u.device;
+ break;
+ case OCON_XEN_DEVICETREE:
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ break;
+ default:
+ /* shouldn't get here */
+ ERR(state->handle, "Unknown ocontext");
+ return -1;
+ }
+ if (context_copy(&n->context[0], &c->context[0],
+ state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_copy_selinux(expand_state_t *state)
+{
+ unsigned int i, j;
+ ocontext_t *c, *n, *l;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ l = NULL;
+ for (c = state->base->ocontexts[i]; c; c = c->next) {
+ n = malloc(sizeof(ocontext_t));
+ if (!n) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(ocontext_t));
+ if (l)
+ l->next = n;
+ else
+ state->out->ocontexts[i] = n;
+ l = n;
+ switch (i) {
+ case OCON_ISID:
+ if (c->context[0].user == 0) {
+ ERR(state->handle,
+ "Missing context for %s initial sid",
+ c->u.name);
+ return -1;
+ }
+ n->sid[0] = c->sid[0];
+ break;
+ case OCON_FS: /* FALLTHROUGH */
+ case OCON_NETIF:
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (context_copy
+ (&n->context[1], &c->context[1], state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_PORT:
+ n->u.port.protocol = c->u.port.protocol;
+ n->u.port.low_port = c->u.port.low_port;
+ n->u.port.high_port = c->u.port.high_port;
+ break;
+ case OCON_NODE:
+ n->u.node.addr = c->u.node.addr;
+ n->u.node.mask = c->u.node.mask;
+ break;
+ case OCON_FSUSE:
+ n->v.behavior = c->v.behavior;
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_NODE6:
+ for (j = 0; j < 4; j++)
+ n->u.node6.addr[j] = c->u.node6.addr[j];
+ for (j = 0; j < 4; j++)
+ n->u.node6.mask[j] = c->u.node6.mask[j];
+ break;
+ default:
+ /* shouldn't get here */
+ ERR(state->handle, "Unknown ocontext");
+ return -1;
+ }
+ if (context_copy(&n->context[0], &c->context[0], state)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_copy(expand_state_t *state, uint32_t target)
+{
+ int rc = -1;
+ switch (target) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_copy_selinux(state);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_copy_xen(state);
+ break;
+ default:
+ ERR(state->handle, "Unknown target");
+ return -1;
+ }
+ return rc;
+}
+
+static int genfs_copy(expand_state_t * state)
+{
+ ocontext_t *c, *newc, *l;
+ genfs_t *genfs, *newgenfs, *end;
+
+ end = NULL;
+ for (genfs = state->base->genfs; genfs; genfs = genfs->next) {
+ newgenfs = malloc(sizeof(genfs_t));
+ if (!newgenfs) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(newgenfs, 0, sizeof(genfs_t));
+ newgenfs->fstype = strdup(genfs->fstype);
+ if (!newgenfs->fstype) {
+ free(newgenfs);
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if (!end)
+ state->out->genfs = newgenfs;
+ else
+ end->next = newgenfs;
+ end = newgenfs;
+
+ l = NULL;
+ for (c = genfs->head; c; c = c->next) {
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+ newc->u.name = strdup(c->u.name);
+ if (!newc->u.name) {
+ ERR(state->handle, "Out of memory!");
+ free(newc);
+ return -1;
+ }
+ newc->v.sclass = c->v.sclass;
+ context_copy(&newc->context[0], &c->context[0], state);
+ if (l)
+ l->next = newc;
+ else
+ newgenfs->head = newc;
+ l = newc;
+ }
+ }
+ return 0;
+}
+
+static int type_attr_map(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *ptr)
+{
+ type_datum_t *type;
+ expand_state_t *state = ptr;
+ policydb_t *p = state->out;
+ unsigned int i;
+ ebitmap_node_t *tnode;
+ int value;
+
+ type = (type_datum_t *) datum;
+ value = type->s.value;
+
+ if (type->flavor == TYPE_ATTRIB) {
+ if (ebitmap_cpy(&p->attr_type_map[value - 1], &type->types)) {
+ goto oom;
+ }
+ ebitmap_for_each_bit(&type->types, tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ if (ebitmap_set_bit(&p->type_attr_map[i], value - 1, 1)) {
+ goto oom;
+ }
+ }
+ } else {
+ if (ebitmap_set_bit(&p->attr_type_map[value - 1], value - 1, 1)) {
+ goto oom;
+ }
+ }
+
+ return 0;
+
+oom:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+/* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy.
+ * this should not be called until after all the blocks have been processed and the attributes in target policy
+ * are complete. */
+int expand_convert_type_set(policydb_t * p, uint32_t * typemap,
+ type_set_t * set, ebitmap_t * types,
+ unsigned char alwaysexpand)
+{
+ type_set_t tmpset;
+
+ type_set_init(&tmpset);
+
+ if (map_ebitmap(&set->types, &tmpset.types, typemap))
+ return -1;
+
+ if (map_ebitmap(&set->negset, &tmpset.negset, typemap))
+ return -1;
+
+ tmpset.flags = set->flags;
+
+ if (type_set_expand(&tmpset, types, p, alwaysexpand))
+ return -1;
+
+ type_set_destroy(&tmpset);
+
+ return 0;
+}
+
+/* Expand a rule into a given avtab - checking for conflicting type
+ * rules. Return 1 on success, 0 if the rule conflicts with something
+ * (and hence was not added), or -1 on error. */
+int expand_rule(sepol_handle_t * handle,
+ policydb_t * source_pol,
+ avrule_t * source_rule, avtab_t * dest_avtab,
+ cond_av_list_t ** cond, cond_av_list_t ** other, int enabled)
+{
+ int retval;
+ ebitmap_t stypes, ttypes;
+
+ if ((source_rule->specified & AVRULE_NEVERALLOW)
+ || (source_rule->specified & AVRULE_XPERMS_NEVERALLOW))
+ return 1;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (type_set_expand(&source_rule->stypes, &stypes, source_pol, 1))
+ return -1;
+ if (type_set_expand(&source_rule->ttypes, &ttypes, source_pol, 1))
+ return -1;
+ retval = expand_rule_helper(handle, source_pol, NULL,
+ source_rule, dest_avtab,
+ cond, other, enabled, &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+/* Expand a role set into an ebitmap containing the roles.
+ * This handles the attribute and flags.
+ * Attribute expansion depends on if the rolemap is available.
+ * During module compile the rolemap is not available, the
+ * possible duplicates of a regular role and the role attribute
+ * the regular role belongs to could be properly handled by
+ * copy_role_trans and copy_role_allow.
+ */
+int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap)
+{
+ unsigned int i;
+ ebitmap_node_t *rnode;
+ ebitmap_t mapped_roles, roles;
+ policydb_t *p = out;
+ role_datum_t *role;
+
+ ebitmap_init(r);
+
+ if (x->flags & ROLE_STAR) {
+ for (i = 0; i < p->p_roles.nprim++; i++)
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ return 0;
+ }
+
+ ebitmap_init(&mapped_roles);
+ ebitmap_init(&roles);
+
+ if (rolemap) {
+ assert(base != NULL);
+ ebitmap_for_each_bit(&x->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ /* take advantage of p_role_val_to_struct[]
+ * of the base module */
+ role = base->role_val_to_struct[i];
+ assert(role != NULL);
+ if (role->flavor == ROLE_ATTRIB) {
+ if (ebitmap_union(&roles,
+ &role->roles))
+ goto bad;
+ } else {
+ if (ebitmap_set_bit(&roles, i, 1))
+ goto bad;
+ }
+ }
+ }
+ if (map_ebitmap(&roles, &mapped_roles, rolemap))
+ goto bad;
+ } else {
+ if (ebitmap_cpy(&mapped_roles, &x->roles))
+ goto bad;
+ }
+
+ ebitmap_for_each_bit(&mapped_roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ if (ebitmap_set_bit(r, i, 1))
+ goto bad;
+ }
+ }
+
+ ebitmap_destroy(&mapped_roles);
+ ebitmap_destroy(&roles);
+
+ /* if role is to be complimented, invert the entire bitmap here */
+ if (x->flags & ROLE_COMP) {
+ for (i = 0; i < ebitmap_length(r); i++) {
+ if (ebitmap_get_bit(r, i)) {
+ if (ebitmap_set_bit(r, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ }
+ }
+ }
+ return 0;
+
+bad:
+ ebitmap_destroy(&mapped_roles);
+ ebitmap_destroy(&roles);
+ return -1;
+}
+
+/* Expand a type set into an ebitmap containing the types. This
+ * handles the negset, attributes, and flags.
+ * Attribute expansion depends on several factors:
+ * - if alwaysexpand is 1, then they will be expanded,
+ * - if the type set has a negset or flags, then they will be expanded,
+ * - otherwise, they will not be expanded.
+ */
+int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p,
+ unsigned char alwaysexpand)
+{
+ unsigned int i;
+ ebitmap_t types, neg_types;
+ ebitmap_node_t *tnode;
+
+ ebitmap_init(&types);
+ ebitmap_init(t);
+
+ if (alwaysexpand || ebitmap_length(&set->negset) || set->flags) {
+ /* First go through the types and OR all the attributes to types */
+ ebitmap_for_each_bit(&set->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ if (p->type_val_to_struct[i]->flavor ==
+ TYPE_ATTRIB) {
+ if (ebitmap_union
+ (&types,
+ &p->type_val_to_struct[i]->
+ types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+ } else {
+ /* No expansion of attributes, just copy the set as is. */
+ if (ebitmap_cpy(&types, &set->types))
+ return -1;
+ }
+
+ /* Now do the same thing for negset */
+ ebitmap_init(&neg_types);
+ ebitmap_for_each_bit(&set->negset, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+ if (ebitmap_union
+ (&neg_types,
+ &p->type_val_to_struct[i]->types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&neg_types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ if (set->flags & TYPE_STAR) {
+ /* set all types not in neg_types */
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_get_bit(&neg_types, i))
+ continue;
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB)
+ continue;
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ goto out;
+ }
+
+ ebitmap_for_each_bit(&types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)
+ && (!ebitmap_get_bit(&neg_types, i)))
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+
+ if (set->flags & TYPE_COMP) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (p->type_val_to_struct[i] &&
+ p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) {
+ assert(!ebitmap_get_bit(t, i));
+ continue;
+ }
+ if (ebitmap_get_bit(t, i)) {
+ if (ebitmap_set_bit(t, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ }
+ }
+
+ out:
+
+ ebitmap_destroy(&types);
+ ebitmap_destroy(&neg_types);
+
+ return 0;
+}
+
+static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
+ avrule_t * source_rule)
+{
+ ebitmap_t stypes, ttypes;
+ avrule_t *avrule;
+ class_perm_node_t *cur_perm, *new_perm, *tail_perm;
+ av_extended_perms_t *xperms = NULL;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->stypes, &stypes, 1))
+ return -1;
+ if (expand_convert_type_set
+ (dest_pol, typemap, &source_rule->ttypes, &ttypes, 1))
+ return -1;
+
+ avrule = (avrule_t *) malloc(sizeof(avrule_t));
+ if (!avrule)
+ return -1;
+
+ avrule_init(avrule);
+ avrule->specified = source_rule->specified;
+ avrule->line = source_rule->line;
+ avrule->flags = source_rule->flags;
+ avrule->source_line = source_rule->source_line;
+ if (source_rule->source_filename) {
+ avrule->source_filename = strdup(source_rule->source_filename);
+ if (!avrule->source_filename)
+ goto err;
+ }
+
+ if (ebitmap_cpy(&avrule->stypes.types, &stypes))
+ goto err;
+
+ if (ebitmap_cpy(&avrule->ttypes.types, &ttypes))
+ goto err;
+
+ cur_perm = source_rule->perms;
+ tail_perm = NULL;
+ while (cur_perm) {
+ new_perm =
+ (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+ if (!new_perm)
+ goto err;
+ class_perm_node_init(new_perm);
+ new_perm->tclass = cur_perm->tclass;
+ assert(new_perm->tclass);
+
+ /* once we have modules with permissions we'll need to map the permissions (and classes) */
+ new_perm->data = cur_perm->data;
+
+ if (!avrule->perms)
+ avrule->perms = new_perm;
+
+ if (tail_perm)
+ tail_perm->next = new_perm;
+ tail_perm = new_perm;
+ cur_perm = cur_perm->next;
+ }
+
+ /* copy over extended permissions */
+ if (source_rule->xperms) {
+ xperms = calloc(1, sizeof(av_extended_perms_t));
+ if (!xperms)
+ goto err;
+ memcpy(xperms, source_rule->xperms, sizeof(av_extended_perms_t));
+ avrule->xperms = xperms;
+ }
+
+ /* just prepend the avrule to the first branch; it'll never be
+ written to disk */
+ if (!dest_pol->global->branch_list->avrules)
+ dest_pol->global->branch_list->avrules = avrule;
+ else {
+ avrule->next = dest_pol->global->branch_list->avrules;
+ dest_pol->global->branch_list->avrules = avrule;
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+
+ return 0;
+
+ err:
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ ebitmap_destroy(&avrule->stypes.types);
+ ebitmap_destroy(&avrule->ttypes.types);
+ cur_perm = avrule->perms;
+ while (cur_perm) {
+ tail_perm = cur_perm->next;
+ free(cur_perm);
+ cur_perm = tail_perm;
+ }
+ free(xperms);
+ free(avrule);
+ return -1;
+}
+
+/*
+ * Expands the avrule blocks for a policy. RBAC rules are copied. Neverallow
+ * rules are copied or expanded as per the settings in the state object; all
+ * other AV rules are expanded. If neverallow rules are expanded, they are not
+ * copied, otherwise they are copied for later use by the assertion checker.
+ */
+static int copy_and_expand_avrule_block(expand_state_t * state)
+{
+ avrule_block_t *curblock = state->base->global;
+ avrule_block_t *prevblock;
+ int retval = -1;
+
+ if (avtab_alloc(&state->out->te_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
+ if (avtab_alloc(&state->out->te_cond_avtab, MAX_AVTAB_SIZE)) {
+ ERR(state->handle, "Out of Memory!");
+ return -1;
+ }
+
+ while (curblock) {
+ avrule_decl_t *decl = curblock->enabled;
+ avrule_t *cur_avrule;
+
+ if (decl == NULL) {
+ /* nothing was enabled within this block */
+ goto cont;
+ }
+
+ /* copy role allows and role trans */
+ if (copy_role_allows(state, decl->role_allow_rules) != 0 ||
+ copy_role_trans(state, decl->role_tr_rules) != 0) {
+ goto cleanup;
+ }
+
+ if (expand_filename_trans(state, decl->filename_trans_rules))
+ goto cleanup;
+
+ /* expand the range transition rules */
+ if (expand_range_trans(state, decl->range_tr_rules))
+ goto cleanup;
+
+ /* copy rules */
+ cur_avrule = decl->avrules;
+ while (cur_avrule != NULL) {
+ if (!(state->expand_neverallow)
+ && cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)) {
+ /* copy this over directly so that assertions are checked later */
+ if (copy_neverallow
+ (state->out, state->typemap, cur_avrule))
+ ERR(state->handle,
+ "Error while copying neverallow.");
+ } else {
+ if (cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))
+ state->out->unsupported_format = 1;
+ if (convert_and_expand_rule
+ (state->handle, state->out, state->typemap,
+ cur_avrule, &state->out->te_avtab, NULL,
+ NULL, 0,
+ state->expand_neverallow) !=
+ EXPAND_RULE_SUCCESS) {
+ goto cleanup;
+ }
+ }
+ cur_avrule = cur_avrule->next;
+ }
+
+ /* copy conditional rules */
+ if (cond_node_copy(state, decl->cond_list))
+ goto cleanup;
+
+ cont:
+ prevblock = curblock;
+ curblock = curblock->next;
+
+ if (state->handle && state->handle->expand_consume_base) {
+ /* set base top avrule block in case there
+ * is an error condition and the policy needs
+ * to be destroyed */
+ state->base->global = curblock;
+ avrule_block_destroy(prevblock);
+ }
+ }
+
+ retval = 0;
+
+ cleanup:
+ return retval;
+}
+
+/*
+ * This function allows external users of the library (such as setools) to
+ * expand only the avrules and optionally perform expansion of neverallow rules
+ * or expand into the same policy for analysis purposes.
+ */
+int expand_module_avrules(sepol_handle_t * handle, policydb_t * base,
+ policydb_t * out, uint32_t * typemap,
+ uint32_t * boolmap, uint32_t * rolemap,
+ uint32_t * usermap, int verbose,
+ int expand_neverallow)
+{
+ expand_state_t state;
+
+ expand_state_init(&state);
+
+ state.base = base;
+ state.out = out;
+ state.typemap = typemap;
+ state.boolmap = boolmap;
+ state.rolemap = rolemap;
+ state.usermap = usermap;
+ state.handle = handle;
+ state.verbose = verbose;
+ state.expand_neverallow = expand_neverallow;
+
+ return copy_and_expand_avrule_block(&state);
+}
+
+static void discard_tunables(sepol_handle_t *sh, policydb_t *pol)
+{
+ avrule_block_t *block;
+ avrule_decl_t *decl;
+ cond_node_t *cur_node;
+ cond_expr_t *cur_expr;
+ int cur_state, preserve_tunables = 0;
+ avrule_t *tail, *to_be_appended;
+
+ if (sh && sh->preserve_tunables)
+ preserve_tunables = 1;
+
+ /* Iterate through all cond_node of all enabled decls, if a cond_node
+ * is about tunable, calculate its state value and concatenate one of
+ * its avrule list to the current decl->avrules list. On the other
+ * hand, the disabled unused branch of a tunable would be discarded.
+ *
+ * Note, such tunable cond_node would be skipped over in expansion,
+ * so we won't have to worry about removing it from decl->cond_list
+ * here :-)
+ *
+ * If tunables are requested to be preserved then they would be
+ * "transformed" as booleans by having their TUNABLE flag cleared.
+ */
+ for (block = pol->global; block != NULL; block = block->next) {
+ decl = block->enabled;
+ if (decl == NULL || decl->enabled == 0)
+ continue;
+
+ tail = decl->avrules;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ for (cur_node = decl->cond_list; cur_node != NULL;
+ cur_node = cur_node->next) {
+ int booleans, tunables, i;
+ cond_bool_datum_t *booldatum;
+ cond_bool_datum_t *tmp[COND_EXPR_MAXDEPTH];
+
+ booleans = tunables = 0;
+ memset(tmp, 0, sizeof(cond_bool_datum_t *) * COND_EXPR_MAXDEPTH);
+
+ for (cur_expr = cur_node->expr; cur_expr != NULL;
+ cur_expr = cur_expr->next) {
+ if (cur_expr->expr_type != COND_BOOL)
+ continue;
+ booldatum = pol->bool_val_to_struct[cur_expr->bool - 1];
+ if (booldatum->flags & COND_BOOL_FLAGS_TUNABLE)
+ tmp[tunables++] = booldatum;
+ else
+ booleans++;
+ }
+
+ /* bool_copy_callback() at link phase has ensured
+ * that no mixture of tunables and booleans in one
+ * expression. However, this would be broken by the
+ * request to preserve tunables */
+ if (!preserve_tunables)
+ assert(!(booleans && tunables));
+
+ if (booleans || preserve_tunables) {
+ cur_node->flags &= ~COND_NODE_FLAGS_TUNABLE;
+ if (tunables) {
+ for (i = 0; i < tunables; i++)
+ tmp[i]->flags &= ~COND_BOOL_FLAGS_TUNABLE;
+ }
+ } else {
+ cur_node->flags |= COND_NODE_FLAGS_TUNABLE;
+ cur_state = cond_evaluate_expr(pol, cur_node->expr);
+ if (cur_state == -1) {
+ printf("Expression result was "
+ "undefined, skipping all"
+ "rules\n");
+ continue;
+ }
+
+ to_be_appended = (cur_state == 1) ?
+ cur_node->avtrue_list : cur_node->avfalse_list;
+
+ if (tail)
+ tail->next = to_be_appended;
+ else
+ tail = decl->avrules = to_be_appended;
+
+ /* Now that the effective branch has been
+ * appended, neutralize its original pointer */
+ if (cur_state == 1)
+ cur_node->avtrue_list = NULL;
+ else
+ cur_node->avfalse_list = NULL;
+
+ /* Update the tail of decl->avrules for
+ * further concatenation */
+ while (tail && tail->next)
+ tail = tail->next;
+ }
+ }
+ }
+}
+
+/* Linking should always be done before calling expand, even if
+ * there is only a base since all optionals are dealt with at link time
+ * the base passed in should be indexed and avrule blocks should be
+ * enabled.
+ */
+int expand_module(sepol_handle_t * handle,
+ policydb_t * base, policydb_t * out, int verbose, int check)
+{
+ int retval = -1;
+ unsigned int i;
+ expand_state_t state;
+ avrule_block_t *curblock;
+
+ /* Append tunable's avtrue_list or avfalse_list to the avrules list
+ * of its home decl depending on its state value, so that the effect
+ * rules of a tunable would be added to te_avtab permanently. Whereas
+ * the disabled unused branch would be discarded.
+ *
+ * Originally this function is called at the very end of link phase,
+ * however, we need to keep the linked policy intact for analysis
+ * purpose. */
+ discard_tunables(handle, base);
+
+ expand_state_init(&state);
+
+ state.verbose = verbose;
+ state.typemap = NULL;
+ state.base = base;
+ state.out = out;
+ state.handle = handle;
+
+ if (base->policy_type != POLICY_BASE) {
+ ERR(handle, "Target of expand was not a base policy.");
+ return -1;
+ }
+
+ state.out->policy_type = POLICY_KERN;
+ state.out->policyvers = POLICYDB_VERSION_MAX;
+
+ /* Copy mls state from base to out */
+ out->mls = base->mls;
+ out->handle_unknown = base->handle_unknown;
+
+ /* Copy target from base to out */
+ out->target_platform = base->target_platform;
+
+ /* Copy policy capabilities */
+ if (ebitmap_cpy(&out->policycaps, &base->policycaps)) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ if ((state.typemap =
+ (uint32_t *) calloc(state.base->p_types.nprim,
+ sizeof(uint32_t))) == NULL) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.boolmap = (uint32_t *)calloc(state.base->p_bools.nprim, sizeof(uint32_t));
+ if (!state.boolmap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.rolemap = (uint32_t *)calloc(state.base->p_roles.nprim, sizeof(uint32_t));
+ if (!state.rolemap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ state.usermap = (uint32_t *)calloc(state.base->p_users.nprim, sizeof(uint32_t));
+ if (!state.usermap) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+
+ /* order is important - types must be first */
+
+ /* copy types */
+ if (hashtab_map(state.base->p_types.table, type_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* convert attribute type sets */
+ if (hashtab_map
+ (state.base->p_types.table, attr_convert_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy commons */
+ if (hashtab_map
+ (state.base->p_commons.table, common_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy classes, note, this does not copy constraints, constraints can't be
+ * copied until after all the blocks have been processed and attributes are complete */
+ if (hashtab_map
+ (state.base->p_classes.table, class_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy type bounds */
+ if (hashtab_map(state.base->p_types.table,
+ type_bounds_copy_callback, &state))
+ goto cleanup;
+
+ /* copy aliases */
+ if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
+ goto cleanup;
+
+ /* index here so that type indexes are available for role_copy_callback */
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* copy roles */
+ if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_roles.table,
+ role_bounds_copy_callback, &state))
+ goto cleanup;
+ /* escalate the type_set_t in a role attribute to all regular roles
+ * that belongs to it. */
+ if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state))
+ goto cleanup;
+
+ /* copy MLS's sensitivity level and categories - this needs to be done
+ * before expanding users (they need to be indexed too) */
+ if (hashtab_map(state.base->p_levels.table, sens_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_cats.table, cats_copy_callback, &state))
+ goto cleanup;
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* copy users */
+ if (hashtab_map(state.base->p_users.table, user_copy_callback, &state))
+ goto cleanup;
+ if (hashtab_map(state.base->p_users.table,
+ user_bounds_copy_callback, &state))
+ goto cleanup;
+
+ /* copy bools */
+ if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state))
+ goto cleanup;
+
+ if (policydb_index_classes(out)) {
+ ERR(handle, "Error while indexing out classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(handle, out, verbose)) {
+ ERR(handle, "Error while indexing out symbols");
+ goto cleanup;
+ }
+
+ /* loop through all decls and union attributes, roles, users */
+ for (curblock = state.base->global; curblock != NULL;
+ curblock = curblock->next) {
+ avrule_decl_t *decl = curblock->enabled;
+
+ if (decl == NULL) {
+ /* nothing was enabled within this block */
+ continue;
+ }
+
+ /* convert attribute type sets */
+ if (hashtab_map
+ (decl->p_types.table, attr_convert_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy roles */
+ if (hashtab_map
+ (decl->p_roles.table, role_copy_callback, &state))
+ goto cleanup;
+
+ /* copy users */
+ if (hashtab_map
+ (decl->p_users.table, user_copy_callback, &state))
+ goto cleanup;
+
+ }
+
+ /* remap role dominates bitmaps */
+ if (hashtab_map(state.out->p_roles.table, role_remap_dominates, &state)) {
+ goto cleanup;
+ }
+
+ if (copy_and_expand_avrule_block(&state) < 0) {
+ ERR(handle, "Error during expand");
+ goto cleanup;
+ }
+
+ /* copy constraints */
+ if (hashtab_map
+ (state.base->p_classes.table, constraint_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ cond_optimize_lists(state.out->cond_list);
+ if (evaluate_conds(state.out))
+ goto cleanup;
+
+ /* copy ocontexts */
+ if (ocontext_copy(&state, out->target_platform))
+ goto cleanup;
+
+ /* copy genfs */
+ if (genfs_copy(&state))
+ goto cleanup;
+
+ /* Build the type<->attribute maps and remove attributes. */
+ state.out->attr_type_map = malloc(state.out->p_types.nprim *
+ sizeof(ebitmap_t));
+ state.out->type_attr_map = malloc(state.out->p_types.nprim *
+ sizeof(ebitmap_t));
+ if (!state.out->attr_type_map || !state.out->type_attr_map) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+ for (i = 0; i < state.out->p_types.nprim; i++) {
+ ebitmap_init(&state.out->type_attr_map[i]);
+ ebitmap_init(&state.out->attr_type_map[i]);
+ /* add the type itself as the degenerate case */
+ if (ebitmap_set_bit(&state.out->type_attr_map[i], i, 1)) {
+ ERR(handle, "Out of memory!");
+ goto cleanup;
+ }
+ }
+ if (hashtab_map(state.out->p_types.table, type_attr_map, &state))
+ goto cleanup;
+ if (check) {
+ if (hierarchy_check_constraints(handle, state.out))
+ goto cleanup;
+
+ if (check_assertions
+ (handle, state.out,
+ state.out->global->branch_list->avrules))
+ goto cleanup;
+ }
+
+ retval = 0;
+
+ cleanup:
+ free(state.typemap);
+ free(state.boolmap);
+ free(state.rolemap);
+ free(state.usermap);
+ return retval;
+}
+
+static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
+{
+ avtab_ptr_t node;
+ avtab_datum_t *avd;
+ avtab_extended_perms_t *xperms;
+ unsigned int i;
+ unsigned int match = 0;
+
+ if (k->specified & AVTAB_XPERMS) {
+ /*
+ * AVTAB_XPERMS entries are not necessarily unique.
+ * find node with matching xperms
+ */
+ node = avtab_search_node(a, k);
+ while (node) {
+ if ((node->datum.xperms->specified == d->xperms->specified) &&
+ (node->datum.xperms->driver == d->xperms->driver)) {
+ match = 1;
+ break;
+ }
+ node = avtab_search_node_next(node, k->specified);
+ }
+ if (!match)
+ node = NULL;
+ } else {
+ node = avtab_search_node(a, k);
+ }
+
+ if (!node || ((k->specified & AVTAB_ENABLED) !=
+ (node->key.specified & AVTAB_ENABLED))) {
+ node = avtab_insert_nonunique(a, k, d);
+ if (!node) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ return 0;
+ }
+
+ avd = &node->datum;
+ xperms = node->datum.xperms;
+ switch (k->specified & ~AVTAB_ENABLED) {
+ case AVTAB_ALLOWED:
+ case AVTAB_AUDITALLOW:
+ avd->data |= d->data;
+ break;
+ case AVTAB_AUDITDENY:
+ avd->data &= d->data;
+ break;
+ case AVTAB_XPERMS_ALLOWED:
+ case AVTAB_XPERMS_AUDITALLOW:
+ case AVTAB_XPERMS_DONTAUDIT:
+ for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+ xperms->perms[i] |= d->xperms->perms[i];
+ break;
+ default:
+ ERR(NULL, "Type conflict!");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct expand_avtab_data {
+ avtab_t *expa;
+ policydb_t *p;
+
+};
+
+static int expand_avtab_node(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+ struct expand_avtab_data *ptr = args;
+ avtab_t *expa = ptr->expa;
+ policydb_t *p = ptr->p;
+ type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+ type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+ ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+ ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ avtab_key_t newkey;
+ int rc;
+
+ newkey.target_class = k->target_class;
+ newkey.specified = k->specified;
+
+ if (stype && ttype && stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) {
+ /* Both are individual types, no expansion required. */
+ return expand_avtab_insert(expa, k, d);
+ }
+
+ if (stype && stype->flavor != TYPE_ATTRIB) {
+ /* Source is an individual type, target is an attribute. */
+ newkey.source_type = k->source_type;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.target_type = j + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (ttype && ttype->flavor != TYPE_ATTRIB) {
+ /* Target is an individual type, source is an attribute. */
+ newkey.target_type = k->target_type;
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ newkey.source_type = i + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Both source and target type are attributes. */
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.source_type = i + 1;
+ newkey.target_type = j + 1;
+ rc = expand_avtab_insert(expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa)
+{
+ struct expand_avtab_data data;
+
+ if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+
+ data.expa = expa;
+ data.p = p;
+ return avtab_map(a, expand_avtab_node, &data);
+}
+
+static int expand_cond_insert(cond_av_list_t ** l,
+ avtab_t * expa,
+ avtab_key_t * k, avtab_datum_t * d)
+{
+ avtab_ptr_t node;
+ avtab_datum_t *avd;
+ cond_av_list_t *nl;
+
+ node = avtab_search_node(expa, k);
+ if (!node ||
+ (k->specified & AVTAB_ENABLED) !=
+ (node->key.specified & AVTAB_ENABLED)) {
+ node = avtab_insert_nonunique(expa, k, d);
+ if (!node) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ node->parse_context = (void *)1;
+ nl = (cond_av_list_t *) malloc(sizeof(*nl));
+ if (!nl) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ memset(nl, 0, sizeof(*nl));
+ nl->node = node;
+ nl->next = *l;
+ *l = nl;
+ return 0;
+ }
+
+ avd = &node->datum;
+ switch (k->specified & ~AVTAB_ENABLED) {
+ case AVTAB_ALLOWED:
+ case AVTAB_AUDITALLOW:
+ avd->data |= d->data;
+ break;
+ case AVTAB_AUDITDENY:
+ avd->data &= d->data;
+ break;
+ default:
+ ERR(NULL, "Type conflict!");
+ return -1;
+ }
+
+ return 0;
+}
+
+int expand_cond_av_node(policydb_t * p,
+ avtab_ptr_t node,
+ cond_av_list_t ** newl, avtab_t * expa)
+{
+ avtab_key_t *k = &node->key;
+ avtab_datum_t *d = &node->datum;
+ type_datum_t *stype = p->type_val_to_struct[k->source_type - 1];
+ type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1];
+ ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1];
+ ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1];
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+ avtab_key_t newkey;
+ int rc;
+
+ newkey.target_class = k->target_class;
+ newkey.specified = k->specified;
+
+ if (stype && ttype && stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) {
+ /* Both are individual types, no expansion required. */
+ return expand_cond_insert(newl, expa, k, d);
+ }
+
+ if (stype && stype->flavor != TYPE_ATTRIB) {
+ /* Source is an individual type, target is an attribute. */
+ newkey.source_type = k->source_type;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.target_type = j + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (ttype && ttype->flavor != TYPE_ATTRIB) {
+ /* Target is an individual type, source is an attribute. */
+ newkey.target_type = k->target_type;
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ newkey.source_type = i + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Both source and target type are attributes. */
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ newkey.source_type = i + 1;
+ newkey.target_type = j + 1;
+ rc = expand_cond_insert(newl, expa, &newkey, d);
+ if (rc)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int expand_cond_av_list(policydb_t * p, cond_av_list_t * l,
+ cond_av_list_t ** newl, avtab_t * expa)
+{
+ cond_av_list_t *cur;
+ avtab_ptr_t node;
+ int rc;
+
+ if (avtab_alloc(expa, MAX_AVTAB_SIZE)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+
+ *newl = NULL;
+ for (cur = l; cur; cur = cur->next) {
+ node = cur->node;
+ rc = expand_cond_av_node(p, node, newl, expa);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/libsepol/src/genbools.c b/libsepol/src/genbools.c
new file mode 100644
index 0000000..c81e848
--- /dev/null
+++ b/libsepol/src/genbools.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+
+/* -- Deprecated -- */
+
+static char *strtrim(char *dest, char *source, int size)
+{
+ int i = 0;
+ char *ptr = source;
+ i = 0;
+ while (isspace(*ptr) && i < size) {
+ ptr++;
+ i++;
+ }
+ strncpy(dest, ptr, size);
+ for (i = strlen(dest) - 1; i > 0; i--) {
+ if (!isspace(dest[i]))
+ break;
+ }
+ dest[i + 1] = '\0';
+ return dest;
+}
+
+static int process_boolean(char *buffer, char *name, int namesize, int *val)
+{
+ char name1[BUFSIZ];
+ char *ptr = NULL;
+ char *tok = strtok_r(buffer, "=", &ptr);
+ if (tok) {
+ strncpy(name1, tok, BUFSIZ - 1);
+ strtrim(name, name1, namesize - 1);
+ if (name[0] == '#')
+ return 0;
+ tok = strtok_r(NULL, "\0", &ptr);
+ if (tok) {
+ while (isspace(*tok))
+ tok++;
+ *val = -1;
+ if (isdigit(tok[0]))
+ *val = atoi(tok);
+ else if (!strncasecmp(tok, "true", sizeof("true") - 1))
+ *val = 1;
+ else if (!strncasecmp
+ (tok, "false", sizeof("false") - 1))
+ *val = 0;
+ if (*val != 0 && *val != 1) {
+ ERR(NULL, "illegal value for boolean "
+ "%s=%s", name, tok);
+ return -1;
+ }
+
+ }
+ }
+ return 1;
+}
+
+static int load_booleans(struct policydb *policydb, const char *path,
+ int *changesp)
+{
+ FILE *boolf;
+ char *buffer = NULL;
+ size_t size = 0;
+ char localbools[BUFSIZ];
+ char name[BUFSIZ];
+ int val;
+ int errors = 0, changes = 0;
+ struct cond_bool_datum *datum;
+
+ boolf = fopen(path, "r");
+ if (boolf == NULL)
+ goto localbool;
+
+#ifdef __APPLE__
+ if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
+ ERR(NULL, "out of memory");
+ return -1;
+ }
+
+ while(fgets(buffer, 255, boolf) != NULL) {
+#else
+ while (getline(&buffer, &size, boolf) > 0) {
+#endif
+ int ret = process_boolean(buffer, name, sizeof(name), &val);
+ if (ret == -1)
+ errors++;
+ if (ret == 1) {
+ datum = hashtab_search(policydb->p_bools.table, name);
+ if (!datum) {
+ ERR(NULL, "unknown boolean %s", name);
+ errors++;
+ continue;
+ }
+ if (datum->state != val) {
+ datum->state = val;
+ changes++;
+ }
+ }
+ }
+ fclose(boolf);
+ localbool:
+ snprintf(localbools, sizeof(localbools), "%s.local", path);
+ boolf = fopen(localbools, "r");
+ if (boolf != NULL) {
+
+#ifdef __APPLE__
+
+ while(fgets(buffer, 255, boolf) != NULL) {
+#else
+
+ while (getline(&buffer, &size, boolf) > 0) {
+#endif
+ int ret =
+ process_boolean(buffer, name, sizeof(name), &val);
+ if (ret == -1)
+ errors++;
+ if (ret == 1) {
+ datum =
+ hashtab_search(policydb->p_bools.table,
+ name);
+ if (!datum) {
+ ERR(NULL, "unknown boolean %s", name);
+ errors++;
+ continue;
+ }
+ if (datum->state != val) {
+ datum->state = val;
+ changes++;
+ }
+ }
+ }
+ fclose(boolf);
+ }
+ free(buffer);
+ if (errors)
+ errno = EINVAL;
+ *changesp = changes;
+ return errors ? -1 : 0;
+}
+
+int sepol_genbools(void *data, size_t len, char *booleans)
+{
+ struct policydb policydb;
+ struct policy_file pf;
+ int rc, changes = 0;
+
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ if (load_booleans(&policydb, booleans, &changes) < 0) {
+ WARN(NULL, "error while reading %s", booleans);
+ }
+
+ if (!changes)
+ goto out;
+
+ if (evaluate_conds(&policydb) < 0) {
+ ERR(NULL, "error while re-evaluating conditionals");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ rc = policydb_write(&policydb, &pf);
+ if (rc) {
+ ERR(NULL, "unable to write new binary policy image");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ out:
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
+
+int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
+{
+ int rc, changes = 0;
+
+ rc = load_booleans(policydb, booleans, &changes);
+ if (!rc && changes)
+ rc = evaluate_conds(policydb);
+ if (rc)
+ errno = EINVAL;
+ return rc;
+}
+
+/* -- End Deprecated -- */
+
+int sepol_genbools_array(void *data, size_t len, char **names, int *values,
+ int nel)
+{
+ struct policydb policydb;
+ struct policy_file pf;
+ int rc, i, errors = 0;
+ struct cond_bool_datum *datum;
+
+ /* Create policy database from image */
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ for (i = 0; i < nel; i++) {
+ datum = hashtab_search(policydb.p_bools.table, names[i]);
+ if (!datum) {
+ ERR(NULL, "boolean %s no longer in policy", names[i]);
+ errors++;
+ continue;
+ }
+ if (values[i] != 0 && values[i] != 1) {
+ ERR(NULL, "illegal value %d for boolean %s",
+ values[i], names[i]);
+ errors++;
+ continue;
+ }
+ datum->state = values[i];
+ }
+
+ if (evaluate_conds(&policydb) < 0) {
+ ERR(NULL, "error while re-evaluating conditionals");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ rc = policydb_write(&policydb, &pf);
+ if (rc) {
+ ERR(NULL, "unable to write binary policy");
+ errno = EINVAL;
+ goto err_destroy;
+ }
+ if (errors) {
+ errno = EINVAL;
+ goto err_destroy;
+ }
+
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
diff --git a/libsepol/src/genusers.c b/libsepol/src/genusers.c
new file mode 100644
index 0000000..0b98a76
--- /dev/null
+++ b/libsepol/src/genusers.c
@@ -0,0 +1,343 @@
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sepol/policydb/policydb.h>
+
+#ifndef __APPLE__
+#include <stdio_ext.h>
+#endif
+
+#include <stdarg.h>
+
+#include "debug.h"
+#include "private.h"
+#include "dso.h"
+#include "mls.h"
+
+/* -- Deprecated -- */
+
+void sepol_set_delusers(int on __attribute((unused)))
+{
+ WARN(NULL, "Deprecated interface");
+}
+
+#undef BADLINE
+#define BADLINE() { \
+ ERR(NULL, "invalid entry %s (%s:%u)", \
+ buffer, path, lineno); \
+ continue; \
+}
+
+static int load_users(struct policydb *policydb, const char *path)
+{
+ FILE *fp;
+ char *buffer = NULL, *p, *q, oldc;
+ size_t len = 0;
+ ssize_t nread;
+ unsigned lineno = 0, islist = 0, bit;
+ user_datum_t *usrdatum;
+ role_datum_t *roldatum;
+ ebitmap_node_t *rnode;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ return -1;
+
+#ifdef __APPLE__
+ if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
+ ERR(NULL, "out of memory");
+ return -1;
+ }
+
+ while(fgets(buffer, 255, fp) != NULL) {
+#else
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+ while ((nread = getline(&buffer, &len, fp)) > 0) {
+#endif
+
+ lineno++;
+ if (buffer[nread - 1] == '\n')
+ buffer[nread - 1] = 0;
+ p = buffer;
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p) || *p == '#')
+ continue;
+
+ if (strncasecmp(p, "user", 4))
+ BADLINE();
+ p += 4;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && !isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ *p++ = 0;
+
+ usrdatum = hashtab_search(policydb->p_users.table, q);
+ if (usrdatum) {
+ /* Replacing an existing user definition. */
+ ebitmap_destroy(&usrdatum->roles.roles);
+ ebitmap_init(&usrdatum->roles.roles);
+ } else {
+ char *id = strdup(q);
+
+ if (!id) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+
+ /* Adding a new user definition. */
+ usrdatum = malloc(sizeof(user_datum_t));
+ if (!usrdatum) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ free(id);
+ fclose(fp);
+ return -1;
+ }
+
+ user_datum_init(usrdatum);
+ usrdatum->s.value = ++policydb->p_users.nprim;
+ if (hashtab_insert(policydb->p_users.table,
+ id, (hashtab_datum_t) usrdatum)) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ free(id);
+ user_datum_destroy(usrdatum);
+ free(usrdatum);
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (strncasecmp(p, "roles", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (*p == '{') {
+ islist = 1;
+ p++;
+ } else
+ islist = 0;
+
+ oldc = 0;
+ do {
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ break;
+
+ q = p;
+ while (*p && *p != ';' && *p != '}' && !isspace(*p))
+ p++;
+ if (!(*p))
+ break;
+ if (*p == '}')
+ islist = 0;
+ oldc = *p;
+ *p++ = 0;
+ if (!q[0])
+ break;
+
+ roldatum = hashtab_search(policydb->p_roles.table, q);
+ if (!roldatum) {
+ ERR(NULL, "undefined role %s (%s:%u)",
+ q, path, lineno);
+ continue;
+ }
+ /* Set the role and every role it dominates */
+ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit))
+ if (ebitmap_set_bit
+ (&usrdatum->roles.roles, bit, 1)) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ }
+ } while (islist);
+ if (oldc == 0)
+ BADLINE();
+
+ if (policydb->mls) {
+ context_struct_t context;
+ char *scontext, *r, *s;
+
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ if (strncasecmp(p, "level", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && strncasecmp(p, "range", 5))
+ p++;
+ if (!(*p))
+ BADLINE();
+ *--p = 0;
+ p++;
+
+ scontext = malloc(p - q);
+ if (!scontext) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ r = scontext;
+ s = q;
+ while (*s) {
+ if (!isspace(*s))
+ *r++ = *s;
+ s++;
+ }
+ *r = 0;
+ r = scontext;
+
+ context_init(&context);
+ if (mls_context_to_sid(policydb, oldc, &r, &context) <
+ 0) {
+ ERR(NULL, "invalid level %s (%s:%u)", scontext,
+ path, lineno);
+ free(scontext);
+ continue;
+
+ }
+ free(scontext);
+ memcpy(&usrdatum->dfltlevel, &context.range.level[0],
+ sizeof(usrdatum->dfltlevel));
+
+ if (strncasecmp(p, "range", 5))
+ BADLINE();
+ p += 5;
+ if (!isspace(*p))
+ BADLINE();
+ while (*p && isspace(*p))
+ p++;
+ if (!(*p))
+ BADLINE();
+ q = p;
+ while (*p && *p != ';')
+ p++;
+ if (!(*p))
+ BADLINE();
+ *p++ = 0;
+
+ scontext = malloc(p - q);
+ if (!scontext) {
+ ERR(NULL, "out of memory");
+ free(buffer);
+ fclose(fp);
+ return -1;
+ }
+ r = scontext;
+ s = q;
+ while (*s) {
+ if (!isspace(*s))
+ *r++ = *s;
+ s++;
+ }
+ *r = 0;
+ r = scontext;
+
+ context_init(&context);
+ if (mls_context_to_sid(policydb, oldc, &r, &context) <
+ 0) {
+ ERR(NULL, "invalid range %s (%s:%u)", scontext,
+ path, lineno);
+ free(scontext);
+ continue;
+ }
+ free(scontext);
+ memcpy(&usrdatum->range, &context.range,
+ sizeof(usrdatum->range));
+ }
+ }
+
+ free(buffer);
+ fclose(fp);
+ return 0;
+}
+
+int sepol_genusers(void *data, size_t len,
+ const char *usersdir, void **newdata, size_t * newlen)
+{
+ struct policydb policydb;
+ char path[PATH_MAX];
+
+ /* Construct policy database */
+ if (policydb_init(&policydb))
+ goto err;
+ if (policydb_from_image(NULL, data, len, &policydb) < 0)
+ goto err;
+
+ /* Load locally defined users. */
+ snprintf(path, sizeof path, "%s/local.users", usersdir);
+ if (load_users(&policydb, path) < 0)
+ goto err_destroy;
+
+ /* Write policy database */
+ if (policydb_to_image(NULL, &policydb, newdata, newlen) < 0)
+ goto err_destroy;
+
+ policydb_destroy(&policydb);
+ return 0;
+
+ err_destroy:
+ policydb_destroy(&policydb);
+
+ err:
+ return -1;
+}
+
+int hidden sepol_genusers_policydb(policydb_t * policydb, const char *usersdir)
+{
+ char path[PATH_MAX];
+
+ /* Load locally defined users. */
+ snprintf(path, sizeof path, "%s/local.users", usersdir);
+ if (load_users(policydb, path) < 0) {
+ ERR(NULL, "unable to load local.users: %s", strerror(errno));
+ return -1;
+ }
+
+ if (policydb_reindex_users(policydb) < 0) {
+ ERR(NULL, "unable to reindex users: %s", strerror(errno));
+ return -1;
+
+ }
+
+ return 0;
+}
+
+/* -- End Deprecated -- */
diff --git a/libsepol/src/handle.c b/libsepol/src/handle.c
new file mode 100644
index 0000000..2e9a4ad
--- /dev/null
+++ b/libsepol/src/handle.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "handle.h"
+#include "debug.h"
+
+sepol_handle_t *sepol_handle_create(void)
+{
+
+ sepol_handle_t *sh = malloc(sizeof(sepol_handle_t));
+ if (sh == NULL)
+ return NULL;
+
+ /* Set callback */
+ sh->msg_callback = sepol_msg_default_handler;
+ sh->msg_callback_arg = NULL;
+
+ /* by default do not disable dontaudits */
+ sh->disable_dontaudit = 0;
+ sh->expand_consume_base = 0;
+
+ /* by default needless unused branch of tunables would be discarded */
+ sh->preserve_tunables = 0;
+
+ return sh;
+}
+
+int sepol_get_preserve_tunables(sepol_handle_t *sh)
+{
+ assert(sh != NULL);
+ return sh->preserve_tunables;
+}
+
+void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables)
+{
+ assert(sh !=NULL);
+ sh->preserve_tunables = preserve_tunables;
+}
+
+int sepol_get_disable_dontaudit(sepol_handle_t *sh)
+{
+ assert(sh !=NULL);
+ return sh->disable_dontaudit;
+}
+
+void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit)
+{
+ assert(sh !=NULL);
+ sh->disable_dontaudit = disable_dontaudit;
+}
+
+void sepol_set_expand_consume_base(sepol_handle_t *sh, int consume_base)
+{
+ assert(sh != NULL);
+ sh->expand_consume_base = consume_base;
+}
+
+void sepol_handle_destroy(sepol_handle_t * sh)
+{
+ free(sh);
+}
diff --git a/libsepol/src/handle.h b/libsepol/src/handle.h
new file mode 100644
index 0000000..7728d04
--- /dev/null
+++ b/libsepol/src/handle.h
@@ -0,0 +1,23 @@
+#ifndef _SEPOL_INTERNAL_HANDLE_H_
+#define _SEPOL_INTERNAL_HANDLE_H_
+
+#include <sepol/handle.h>
+
+struct sepol_handle {
+ /* Error handling */
+ int msg_level;
+ const char *msg_channel;
+ const char *msg_fname;
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ void (*msg_callback) (void *varg,
+ sepol_handle_t * handle, const char *fmt, ...);
+ void *msg_callback_arg;
+
+ int disable_dontaudit;
+ int expand_consume_base;
+ int preserve_tunables;
+};
+
+#endif
diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
new file mode 100644
index 0000000..c4be72c
--- /dev/null
+++ b/libsepol/src/hashtab.c
@@ -0,0 +1,313 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/* FLASK */
+
+/*
+ * Implementation of the hash table type.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+
+hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
+ const hashtab_key_t key),
+ int (*keycmp) (hashtab_t h,
+ const hashtab_key_t key1,
+ const hashtab_key_t key2),
+ unsigned int size)
+{
+
+ hashtab_t p;
+ unsigned int i;
+
+ p = (hashtab_t) malloc(sizeof(hashtab_val_t));
+ if (p == NULL)
+ return p;
+
+ memset(p, 0, sizeof(hashtab_val_t));
+ p->size = size;
+ p->nel = 0;
+ p->hash_value = hash_value;
+ p->keycmp = keycmp;
+ p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
+ if (p->htable == NULL) {
+ free(p);
+ return NULL;
+ }
+ for (i = 0; i < size; i++)
+ p->htable[i] = (hashtab_ptr_t) NULL;
+
+ return p;
+}
+
+int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
+{
+ int hvalue;
+ hashtab_ptr_t prev, cur, newnode;
+
+ if (!h)
+ return SEPOL_ENOMEM;
+
+ hvalue = h->hash_value(h, key);
+ prev = NULL;
+ cur = h->htable[hvalue];
+ while (cur && h->keycmp(h, key, cur->key) > 0) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && (h->keycmp(h, key, cur->key) == 0))
+ return SEPOL_EEXIST;
+
+ newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+ if (newnode == NULL)
+ return SEPOL_ENOMEM;
+ memset(newnode, 0, sizeof(struct hashtab_node));
+ newnode->key = key;
+ newnode->datum = datum;
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+
+ h->nel++;
+ return SEPOL_OK;
+}
+
+int hashtab_remove(hashtab_t h, hashtab_key_t key,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ int hvalue;
+ hashtab_ptr_t cur, last;
+
+ if (!h)
+ return SEPOL_ENOENT;
+
+ hvalue = h->hash_value(h, key);
+ last = NULL;
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+ last = cur;
+ cur = cur->next;
+ }
+
+ if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+ return SEPOL_ENOENT;
+
+ if (last == NULL)
+ h->htable[hvalue] = cur->next;
+ else
+ last->next = cur->next;
+
+ if (destroy)
+ destroy(cur->key, cur->datum, args);
+ free(cur);
+ h->nel--;
+ return SEPOL_OK;
+}
+
+int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum,
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ int hvalue;
+ hashtab_ptr_t prev, cur, newnode;
+
+ if (!h)
+ return SEPOL_ENOMEM;
+
+ hvalue = h->hash_value(h, key);
+ prev = NULL;
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && (h->keycmp(h, key, cur->key) == 0)) {
+ if (destroy)
+ destroy(cur->key, cur->datum, args);
+ cur->key = key;
+ cur->datum = datum;
+ } else {
+ newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
+ if (newnode == NULL)
+ return SEPOL_ENOMEM;
+ memset(newnode, 0, sizeof(struct hashtab_node));
+ newnode->key = key;
+ newnode->datum = datum;
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = h->htable[hvalue];
+ h->htable[hvalue] = newnode;
+ }
+ }
+
+ return SEPOL_OK;
+}
+
+hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key)
+{
+
+ int hvalue;
+ hashtab_ptr_t cur;
+
+ if (!h)
+ return NULL;
+
+ hvalue = h->hash_value(h, key);
+ cur = h->htable[hvalue];
+ while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+ cur = cur->next;
+
+ if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+ return NULL;
+
+ return cur->datum;
+}
+
+void hashtab_destroy(hashtab_t h)
+{
+ unsigned int i;
+ hashtab_ptr_t cur, temp;
+
+ if (!h)
+ return;
+
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ free(temp);
+ }
+ h->htable[i] = NULL;
+ }
+
+ free(h->htable);
+ h->htable = NULL;
+
+ free(h);
+}
+
+int hashtab_map(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d, void *args), void *args)
+{
+ unsigned int i, ret;
+ hashtab_ptr_t cur;
+
+ if (!h)
+ return SEPOL_OK;
+
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->key, cur->datum, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return SEPOL_OK;
+}
+
+void hashtab_map_remove_on_error(hashtab_t h,
+ int (*apply) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args),
+ void (*destroy) (hashtab_key_t k,
+ hashtab_datum_t d,
+ void *args), void *args)
+{
+ unsigned int i;
+ int ret;
+ hashtab_ptr_t last, cur, temp;
+
+ if (!h)
+ return;
+
+ for (i = 0; i < h->size; i++) {
+ last = NULL;
+ cur = h->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->key, cur->datum, args);
+ if (ret) {
+ if (last) {
+ last->next = cur->next;
+ } else {
+ h->htable[i] = cur->next;
+ }
+
+ temp = cur;
+ cur = cur->next;
+ if (destroy)
+ destroy(temp->key, temp->datum, args);
+ free(temp);
+ h->nel--;
+ } else {
+ last = cur;
+ cur = cur->next;
+ }
+ }
+ }
+
+ return;
+}
+
+void hashtab_hash_eval(hashtab_t h, char *tag)
+{
+ unsigned int i;
+ int chain_len, slots_used, max_chain_len;
+ hashtab_ptr_t cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < h->size; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, h->size, max_chain_len);
+}
diff --git a/libsepol/src/hierarchy.c b/libsepol/src/hierarchy.c
new file mode 100644
index 0000000..778541a
--- /dev/null
+++ b/libsepol/src/hierarchy.c
@@ -0,0 +1,702 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Updates: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * adds checks based on newer boundary facility.
+ *
+ * A set of utility functions that aid policy decision when dealing
+ * with hierarchal namespaces.
+ *
+ * Copyright (C) 2005 Tresys Technology, LLC
+ *
+ * Copyright (c) 2008 NEC Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hierarchy.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+
+#define BOUNDS_AVTAB_SIZE 1024
+
+static int bounds_insert_helper(sepol_handle_t *handle, avtab_t *avtab,
+ avtab_key_t *avtab_key, avtab_datum_t *datum)
+{
+ int rc = avtab_insert(avtab, avtab_key, datum);
+ if (rc) {
+ if (rc == SEPOL_ENOMEM)
+ ERR(handle, "Insufficient memory");
+ else
+ ERR(handle, "Unexpected error (%d)", rc);
+ }
+ return rc;
+}
+
+
+static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
+ avtab_t *global, avtab_t *other,
+ avtab_key_t *avtab_key, avtab_datum_t *datum)
+{
+ int rc = 0;
+ avtab_datum_t *dup = avtab_search(avtab, avtab_key);
+
+ if (!dup) {
+ rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
+ if (rc) goto exit;
+ } else {
+ dup->data |= datum->data;
+ }
+
+ if (other) {
+ /* Search the other conditional avtab for the key and
+ * add any common permissions to the global avtab
+ */
+ uint32_t data = 0;
+ dup = avtab_search(other, avtab_key);
+ if (dup) {
+ data = dup->data & datum->data;
+ if (data) {
+ dup = avtab_search(global, avtab_key);
+ if (!dup) {
+ avtab_datum_t d;
+ d.data = data;
+ rc = bounds_insert_helper(handle, global,
+ avtab_key, &d);
+ if (rc) goto exit;
+ } else {
+ dup->data |= data;
+ }
+ }
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
+ avtab_t *avtab, avtab_t *global, avtab_t *other,
+ uint32_t parent, uint32_t src, uint32_t tgt,
+ uint32_t class, uint32_t data)
+{
+ int rc = 0;
+ avtab_key_t avtab_key;
+ avtab_datum_t datum;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+
+ avtab_key.specified = AVTAB_ALLOWED;
+ avtab_key.target_class = class;
+ datum.data = data;
+
+ if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
+ avtab_key.source_type = parent;
+ ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ avtab_key.target_type = i + 1;
+ rc = bounds_insert_rule(handle, avtab, global, other,
+ &avtab_key, &datum);
+ if (rc) goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
+ cond_av_list_t *cur, avtab_t *avtab,
+ avtab_t *global, avtab_t *other,
+ uint32_t parent)
+{
+ int rc = 0;
+
+ for (; cur; cur = cur->next) {
+ avtab_ptr_t n = cur->node;
+ rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
+ n->key.source_type, n->key.target_type,
+ n->key.target_class, n->datum.data);
+ if (rc) goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+struct bounds_expand_args {
+ sepol_handle_t *handle;
+ policydb_t *p;
+ avtab_t *avtab;
+ uint32_t parent;
+};
+
+static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
+ void *args)
+{
+ struct bounds_expand_args *a = (struct bounds_expand_args *)args;
+
+ if (!(k->specified & AVTAB_ALLOWED))
+ return 0;
+
+ return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
+ a->parent, k->source_type, k->target_type,
+ k->target_class, d->data);
+}
+
+struct bounds_cond_info {
+ avtab_t true_avtab;
+ avtab_t false_avtab;
+ cond_list_t *cond_list;
+ struct bounds_cond_info *next;
+};
+
+static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
+{
+ struct bounds_cond_info *next;
+
+ for (; cur; cur = next) {
+ next = cur->next;
+ avtab_destroy(&cur->true_avtab);
+ avtab_destroy(&cur->false_avtab);
+ cur->next = NULL;
+ free(cur);
+ }
+}
+
+static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
+ avtab_t *global_avtab,
+ struct bounds_cond_info **cond_info,
+ uint32_t parent)
+{
+ int rc = 0;
+ struct bounds_expand_args args;
+ cond_list_t *cur;
+
+ avtab_init(global_avtab);
+ rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
+ if (rc) goto oom;
+
+ args.handle = handle;
+ args.p = p;
+ args.avtab = global_avtab;
+ args.parent = parent;
+ rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
+ if (rc) goto exit;
+
+ *cond_info = NULL;
+ for (cur = p->cond_list; cur; cur = cur->next) {
+ struct bounds_cond_info *ci;
+ ci = malloc(sizeof(struct bounds_cond_info));
+ if (!ci) goto oom;
+ avtab_init(&ci->true_avtab);
+ avtab_init(&ci->false_avtab);
+ ci->cond_list = cur;
+ ci->next = *cond_info;
+ *cond_info = ci;
+ if (cur->true_list) {
+ rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
+ if (rc) goto oom;
+ rc = bounds_expand_cond_rules(handle, p, cur->true_list,
+ &ci->true_avtab, NULL,
+ NULL, parent);
+ if (rc) goto exit;
+ }
+ if (cur->false_list) {
+ rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
+ if (rc) goto oom;
+ rc = bounds_expand_cond_rules(handle, p, cur->false_list,
+ &ci->false_avtab,
+ global_avtab,
+ &ci->true_avtab, parent);
+ if (rc) goto exit;
+ }
+ }
+
+ return 0;
+
+oom:
+ ERR(handle, "Insufficient memory");
+
+exit:
+ ERR(handle,"Failed to expand parent rules\n");
+ avtab_destroy(global_avtab);
+ bounds_destroy_cond_info(*cond_info);
+ *cond_info = NULL;
+ return rc;
+}
+
+static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
+ avtab_key_t *avtab_key, uint32_t data)
+{
+ avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
+ if (datum)
+ data &= ~datum->data;
+ if (global_avtab && data) {
+ datum = avtab_search(global_avtab, avtab_key);
+ if (datum)
+ data &= ~datum->data;
+ }
+
+ return data;
+}
+
+static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
+ uint32_t class, uint32_t data, avtab_ptr_t *bad)
+{
+ struct avtab_node *new = malloc(sizeof(struct avtab_node));
+ if (new == NULL) {
+ ERR(handle, "Insufficient memory");
+ return SEPOL_ENOMEM;
+ }
+ memset(new, 0, sizeof(struct avtab_node));
+ new->key.source_type = src;
+ new->key.target_type = tgt;
+ new->key.target_class = class;
+ new->datum.data = data;
+ new->next = *bad;
+ *bad = new;
+
+ return 0;
+}
+
+static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
+ avtab_t *global_avtab, avtab_t *cur_avtab,
+ uint32_t child, uint32_t parent, uint32_t src,
+ uint32_t tgt, uint32_t class, uint32_t data,
+ avtab_ptr_t *bad, int *numbad)
+{
+ int rc = 0;
+ avtab_key_t avtab_key;
+ type_datum_t *td;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ uint32_t d;
+
+ avtab_key.specified = AVTAB_ALLOWED;
+ avtab_key.target_class = class;
+
+ if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
+ avtab_key.source_type = parent;
+ ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
+ if (!ebitmap_node_get_bit(tnode, i))
+ continue;
+ td = p->type_val_to_struct[i];
+ if (td && td->bounds) {
+ avtab_key.target_type = td->bounds;
+ d = bounds_not_covered(global_avtab, cur_avtab,
+ &avtab_key, data);
+ } else {
+ avtab_key.target_type = i + 1;
+ d = bounds_not_covered(global_avtab, cur_avtab,
+ &avtab_key, data);
+ }
+ if (d) {
+ (*numbad)++;
+ rc = bounds_add_bad(handle, child, i+1, class, d, bad);
+ if (rc) goto exit;
+ }
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
+ avtab_t *global_avtab, avtab_t *cond_avtab,
+ cond_av_list_t *rules, uint32_t child,
+ uint32_t parent, avtab_ptr_t *bad,
+ int *numbad)
+{
+ int rc = 0;
+ cond_av_list_t *cur;
+
+ for (cur = rules; cur; cur = cur->next) {
+ avtab_ptr_t ap = cur->node;
+ avtab_key_t *key = &ap->key;
+ avtab_datum_t *datum = &ap->datum;
+ if (!(key->specified & AVTAB_ALLOWED))
+ continue;
+ rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
+ child, parent, key->source_type,
+ key->target_type, key->target_class,
+ datum->data, bad, numbad);
+ if (rc) goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+struct bounds_check_args {
+ sepol_handle_t *handle;
+ policydb_t *p;
+ avtab_t *cur_avtab;
+ uint32_t child;
+ uint32_t parent;
+ avtab_ptr_t bad;
+ int numbad;
+};
+
+static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
+ void *args)
+{
+ struct bounds_check_args *a = (struct bounds_check_args *)args;
+
+ if (!(k->specified & AVTAB_ALLOWED))
+ return 0;
+
+ return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
+ a->parent, k->source_type, k->target_type,
+ k->target_class, d->data, &a->bad, &a->numbad);
+}
+
+static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
+ avtab_t *global_avtab,
+ struct bounds_cond_info *cond_info,
+ uint32_t child, uint32_t parent,
+ avtab_ptr_t *bad, int *numbad)
+{
+ int rc;
+ struct bounds_check_args args;
+ struct bounds_cond_info *cur;
+
+ args.handle = handle;
+ args.p = p;
+ args.cur_avtab = global_avtab;
+ args.child = child;
+ args.parent = parent;
+ args.bad = NULL;
+ args.numbad = 0;
+ rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
+ if (rc) goto exit;
+
+ for (cur = cond_info; cur; cur = cur->next) {
+ cond_list_t *node = cur->cond_list;
+ rc = bounds_check_cond_rules(handle, p, global_avtab,
+ &cur->true_avtab,
+ node->true_list, child, parent,
+ &args.bad, &args.numbad);
+ if (rc) goto exit;
+
+ rc = bounds_check_cond_rules(handle, p, global_avtab,
+ &cur->false_avtab,
+ node->false_list, child, parent,
+ &args.bad, &args.numbad);
+ if (rc) goto exit;
+ }
+
+ *numbad += args.numbad;
+ *bad = args.bad;
+
+exit:
+ return rc;
+}
+
+int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+ uint32_t parent, avtab_ptr_t *bad, int *numbad)
+{
+ int rc = 0;
+ avtab_t global_avtab;
+ struct bounds_cond_info *cond_info = NULL;
+
+ rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
+ if (rc) goto exit;
+
+ rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
+ child, parent, bad, numbad);
+
+ bounds_destroy_cond_info(cond_info);
+ avtab_destroy(&global_avtab);
+
+exit:
+ return rc;
+}
+
+struct bounds_args {
+ sepol_handle_t *handle;
+ policydb_t *p;
+ int numbad;
+};
+
+static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
+ uint32_t parent, avtab_ptr_t cur)
+{
+ ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
+ p->p_type_val_to_name[child - 1],
+ p->p_type_val_to_name[parent - 1]);
+ for (; cur; cur = cur->next) {
+ ERR(handle, " %s %s : %s { %s }",
+ p->p_type_val_to_name[cur->key.source_type - 1],
+ p->p_type_val_to_name[cur->key.target_type - 1],
+ p->p_class_val_to_name[cur->key.target_class - 1],
+ sepol_av_to_string(p, cur->key.target_class,
+ cur->datum.data));
+ }
+}
+
+void bounds_destroy_bad(avtab_ptr_t cur)
+{
+ avtab_ptr_t next;
+
+ for (; cur; cur = next) {
+ next = cur->next;
+ cur->next = NULL;
+ free(cur);
+ }
+}
+
+static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
+ hashtab_datum_t d, void *args)
+{
+ int rc = 0;
+ struct bounds_args *a = (struct bounds_args *)args;
+ type_datum_t *t = (type_datum_t *)d;
+ avtab_ptr_t bad = NULL;
+
+ if (t->bounds) {
+ rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
+ &bad, &a->numbad);
+ if (bad) {
+ bounds_report(a->handle, a->p, t->s.value, t->bounds,
+ bad);
+ bounds_destroy_bad(bad);
+ }
+ }
+
+ return rc;
+}
+
+int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
+{
+ int rc;
+ struct bounds_args args;
+
+ args.handle = handle;
+ args.p = p;
+ args.numbad = 0;
+
+ rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
+ if (rc) goto exit;
+
+ if (args.numbad > 0) {
+ ERR(handle, "%d errors found during type bounds check",
+ args.numbad);
+ rc = SEPOL_ERR;
+ }
+
+exit:
+ return rc;
+}
+
+/* The role bounds is defined as: a child role cannot have a type that
+ * its parent doesn't have.
+ */
+static int bounds_check_role_callback(hashtab_key_t k,
+ hashtab_datum_t d, void *args)
+{
+ struct bounds_args *a = (struct bounds_args *)args;
+ role_datum_t *r = (role_datum_t *) d;
+ role_datum_t *rp = NULL;
+
+ if (!r->bounds)
+ return 0;
+
+ rp = a->p->role_val_to_struct[r->bounds - 1];
+
+ if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
+ ERR(a->handle, "Role bounds violation, %s exceeds %s",
+ (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
+ a->numbad++;
+ }
+
+ return 0;
+}
+
+int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
+{
+ struct bounds_args args;
+
+ args.handle = handle;
+ args.p = p;
+ args.numbad = 0;
+
+ hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
+
+ if (args.numbad > 0) {
+ ERR(handle, "%d errors found during role bounds check",
+ args.numbad);
+ return SEPOL_ERR;
+ }
+
+ return 0;
+}
+
+/* The user bounds is defined as: a child user cannot have a role that
+ * its parent doesn't have.
+ */
+static int bounds_check_user_callback(hashtab_key_t k,
+ hashtab_datum_t d, void *args)
+{
+ struct bounds_args *a = (struct bounds_args *)args;
+ user_datum_t *u = (user_datum_t *) d;
+ user_datum_t *up = NULL;
+
+ if (!u->bounds)
+ return 0;
+
+ up = a->p->user_val_to_struct[u->bounds - 1];
+
+ if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
+ ERR(a->handle, "User bounds violation, %s exceeds %s",
+ (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
+ a->numbad++;
+ }
+
+ return 0;
+}
+
+int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
+{
+ struct bounds_args args;
+
+ args.handle = handle;
+ args.p = p;
+ args.numbad = 0;
+
+ hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
+
+ if (args.numbad > 0) {
+ ERR(handle, "%d errors found during user bounds check",
+ args.numbad);
+ return SEPOL_ERR;
+ }
+
+ return 0;
+}
+
+#define add_hierarchy_callback_template(prefix) \
+ int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
+ hashtab_datum_t d, void *args) \
+{ \
+ struct bounds_args *a = (struct bounds_args *)args; \
+ sepol_handle_t *handle = a->handle; \
+ policydb_t *p = a->p; \
+ prefix##_datum_t *datum = (prefix##_datum_t *)d; \
+ prefix##_datum_t *parent; \
+ char *parent_name, *datum_name, *tmp; \
+ \
+ if (!datum->bounds) { \
+ datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
+ \
+ tmp = strrchr(datum_name, '.'); \
+ /* no '.' means it has no parent */ \
+ if (!tmp) return 0; \
+ \
+ parent_name = strdup(datum_name); \
+ if (!parent_name) { \
+ ERR(handle, "Insufficient memory"); \
+ return SEPOL_ENOMEM; \
+ } \
+ parent_name[tmp - datum_name] = '\0'; \
+ \
+ parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
+ if (!parent) { \
+ /* Orphan type/role/user */ \
+ ERR(handle, "%s doesn't exist, %s is an orphan",\
+ parent_name, \
+ p->p_##prefix##_val_to_name[datum->s.value - 1]); \
+ free(parent_name); \
+ a->numbad++; \
+ return 0; \
+ } \
+ datum->bounds = parent->s.value; \
+ free(parent_name); \
+ } \
+ \
+ return 0; \
+} \
+
+static add_hierarchy_callback_template(type)
+static add_hierarchy_callback_template(role)
+static add_hierarchy_callback_template(user)
+
+int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
+{
+ int rc = 0;
+ struct bounds_args args;
+
+ args.handle = handle;
+ args.p = p;
+ args.numbad = 0;
+
+ rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
+ if (rc) goto exit;
+
+ rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
+ if (rc) goto exit;
+
+ rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
+ if (rc) goto exit;
+
+ if (args.numbad > 0) {
+ ERR(handle, "%d errors found while adding hierarchies",
+ args.numbad);
+ rc = SEPOL_ERR;
+ }
+
+exit:
+ return rc;
+}
+
+int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
+{
+ int rc = 0;
+ int violation = 0;
+
+ rc = hierarchy_add_bounds(handle, p);
+ if (rc) goto exit;
+
+ rc = bounds_check_users(handle, p);
+ if (rc)
+ violation = 1;
+
+ rc = bounds_check_roles(handle, p);
+ if (rc)
+ violation = 1;
+
+ rc = bounds_check_types(handle, p);
+ if (rc) {
+ if (rc == SEPOL_ERR)
+ violation = 1;
+ else
+ goto exit;
+ }
+
+ if (violation)
+ rc = SEPOL_ERR;
+
+exit:
+ return rc;
+}
diff --git a/libsepol/src/iface_internal.h b/libsepol/src/iface_internal.h
new file mode 100644
index 0000000..5b78d9b
--- /dev/null
+++ b/libsepol/src/iface_internal.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_IFACE_INTERNAL_H_
+#define _SEPOL_IFACE_INTERNAL_H_
+
+#include <sepol/iface_record.h>
+#include <sepol/interfaces.h>
+#include "dso.h"
+
+hidden_proto(sepol_iface_create)
+ hidden_proto(sepol_iface_free)
+ hidden_proto(sepol_iface_get_ifcon)
+ hidden_proto(sepol_iface_get_msgcon)
+ hidden_proto(sepol_iface_get_name)
+ hidden_proto(sepol_iface_key_create)
+ hidden_proto(sepol_iface_key_unpack)
+ hidden_proto(sepol_iface_set_ifcon)
+ hidden_proto(sepol_iface_set_msgcon)
+ hidden_proto(sepol_iface_set_name)
+#endif
diff --git a/libsepol/src/iface_record.c b/libsepol/src/iface_record.c
new file mode 100644
index 0000000..09adeb7
--- /dev/null
+++ b/libsepol/src/iface_record.c
@@ -0,0 +1,233 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "iface_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_iface {
+
+ /* Interface name */
+ char *name;
+
+ /* Interface context */
+ sepol_context_t *netif_con;
+
+ /* Message context */
+ sepol_context_t *netmsg_con;
+};
+
+struct sepol_iface_key {
+
+ /* Interface name */
+ const char *name;
+};
+
+/* Key */
+int sepol_iface_key_create(sepol_handle_t * handle,
+ const char *name, sepol_iface_key_t ** key_ptr)
+{
+
+ sepol_iface_key_t *tmp_key =
+ (sepol_iface_key_t *) malloc(sizeof(sepol_iface_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, could not create interface key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_key_create)
+
+void sepol_iface_key_unpack(const sepol_iface_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_iface_key_unpack)
+
+int sepol_iface_key_extract(sepol_handle_t * handle,
+ const sepol_iface_t * iface,
+ sepol_iface_key_t ** key_ptr)
+{
+
+ if (sepol_iface_key_create(handle, iface->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from "
+ "interface %s", iface->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_iface_key_free(sepol_iface_key_t * key)
+{
+ free(key);
+}
+
+int sepol_iface_compare(const sepol_iface_t * iface,
+ const sepol_iface_key_t * key)
+{
+
+ return strcmp(iface->name, key->name);
+}
+
+int sepol_iface_compare2(const sepol_iface_t * iface,
+ const sepol_iface_t * iface2)
+{
+
+ return strcmp(iface->name, iface2->name);
+}
+
+/* Create */
+int sepol_iface_create(sepol_handle_t * handle, sepol_iface_t ** iface)
+{
+
+ sepol_iface_t *tmp_iface =
+ (sepol_iface_t *) malloc(sizeof(sepol_iface_t));
+
+ if (!tmp_iface) {
+ ERR(handle, "out of memory, could not create "
+ "interface record");
+ return STATUS_ERR;
+ }
+
+ tmp_iface->name = NULL;
+ tmp_iface->netif_con = NULL;
+ tmp_iface->netmsg_con = NULL;
+ *iface = tmp_iface;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_create)
+
+/* Name */
+const char *sepol_iface_get_name(const sepol_iface_t * iface)
+{
+
+ return iface->name;
+}
+
+hidden_def(sepol_iface_get_name)
+
+int sepol_iface_set_name(sepol_handle_t * handle,
+ sepol_iface_t * iface, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, " "could not set interface name");
+ return STATUS_ERR;
+ }
+ free(iface->name);
+ iface->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_name)
+
+/* Interface Context */
+sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface)
+{
+
+ return iface->netif_con;
+}
+
+hidden_def(sepol_iface_get_ifcon)
+
+int sepol_iface_set_ifcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set interface context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(iface->netif_con);
+ iface->netif_con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_ifcon)
+
+/* Message Context */
+sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface)
+{
+
+ return iface->netmsg_con;
+}
+
+hidden_def(sepol_iface_get_msgcon)
+
+int sepol_iface_set_msgcon(sepol_handle_t * handle,
+ sepol_iface_t * iface, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set message context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(iface->netmsg_con);
+ iface->netmsg_con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_iface_set_msgcon)
+
+/* Deep copy clone */
+int sepol_iface_clone(sepol_handle_t * handle,
+ const sepol_iface_t * iface, sepol_iface_t ** iface_ptr)
+{
+
+ sepol_iface_t *new_iface = NULL;
+ if (sepol_iface_create(handle, &new_iface) < 0)
+ goto err;
+
+ if (sepol_iface_set_name(handle, new_iface, iface->name) < 0)
+ goto err;
+
+ if (iface->netif_con &&
+ (sepol_context_clone
+ (handle, iface->netif_con, &new_iface->netif_con) < 0))
+ goto err;
+
+ if (iface->netmsg_con &&
+ (sepol_context_clone
+ (handle, iface->netmsg_con, &new_iface->netmsg_con) < 0))
+ goto err;
+
+ *iface_ptr = new_iface;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone interface record");
+ sepol_iface_free(new_iface);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_iface_free(sepol_iface_t * iface)
+{
+
+ if (!iface)
+ return;
+
+ free(iface->name);
+ sepol_context_free(iface->netif_con);
+ sepol_context_free(iface->netmsg_con);
+ free(iface);
+}
+
+hidden_def(sepol_iface_free)
diff --git a/libsepol/src/interfaces.c b/libsepol/src/interfaces.c
new file mode 100644
index 0000000..f371d0b
--- /dev/null
+++ b/libsepol/src/interfaces.c
@@ -0,0 +1,271 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/interfaces.h>
+#include "iface_internal.h"
+
+/* Create a low level structure from record */
+static int iface_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** iface, const sepol_iface_t * record)
+{
+
+ ocontext_t *tmp_iface = NULL;
+ context_struct_t *tmp_con = NULL;
+
+ tmp_iface = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_iface)
+ goto omem;
+
+ /* Name */
+ tmp_iface->u.name = strdup(sepol_iface_get_name(record));
+ if (!tmp_iface->u.name)
+ goto omem;
+
+ /* Interface Context */
+ if (context_from_record(handle, policydb,
+ &tmp_con, sepol_iface_get_ifcon(record)) < 0)
+ goto err;
+ context_cpy(&tmp_iface->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ /* Message Context */
+ if (context_from_record(handle, policydb,
+ &tmp_con, sepol_iface_get_msgcon(record)) < 0)
+ goto err;
+ context_cpy(&tmp_iface->context[1], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *iface = tmp_iface;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_iface != NULL) {
+ free(tmp_iface->u.name);
+ context_destroy(&tmp_iface->context[0]);
+ context_destroy(&tmp_iface->context[1]);
+ free(tmp_iface);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ ERR(handle, "error creating interface structure");
+ return STATUS_ERR;
+}
+
+static int iface_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * iface, sepol_iface_t ** record)
+{
+
+ char *name = iface->u.name;
+ context_struct_t *ifcon = &iface->context[0];
+ context_struct_t *msgcon = &iface->context[1];
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_iface_t *tmp_record = NULL;
+
+ if (sepol_iface_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_iface_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ if (context_to_record(handle, policydb, ifcon, &tmp_con) < 0)
+ goto err;
+ if (sepol_iface_set_ifcon(handle, tmp_record, tmp_con) < 0)
+ goto err;
+ sepol_context_free(tmp_con);
+ tmp_con = NULL;
+
+ if (context_to_record(handle, policydb, msgcon, &tmp_con) < 0)
+ goto err;
+ if (sepol_iface_set_msgcon(handle, tmp_record, tmp_con) < 0)
+ goto err;
+ sepol_context_free(tmp_con);
+ tmp_con = NULL;
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert interface %s to record", name);
+ sepol_context_free(tmp_con);
+ sepol_iface_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Check if an interface exists */
+int sepol_iface_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p,
+ const sepol_iface_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ *response = 0;
+
+ return STATUS_SUCCESS;
+}
+
+/* Query an interface */
+int sepol_iface_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_iface_key_t * key, sepol_iface_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+
+ if (iface_to_record(handle, policydb, c, response) < 0)
+ goto err;
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query interface %s", name);
+ return STATUS_ERR;
+}
+
+/* Load an interface into policy */
+int sepol_iface_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_iface_key_t * key,
+ const sepol_iface_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *head, *prev, *c, *iface = NULL;
+
+ const char *name;
+ sepol_iface_key_unpack(key, &name);
+
+ if (iface_from_record(handle, policydb, &iface, data) < 0)
+ goto err;
+
+ prev = NULL;
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(name, c->u.name)) {
+
+ /* Replace */
+ iface->next = c->next;
+ if (prev == NULL)
+ policydb->ocontexts[OCON_NETIF] = iface;
+ else
+ prev->next = iface;
+ free(c->u.name);
+ context_destroy(&c->context[0]);
+ context_destroy(&c->context[1]);
+ free(c);
+
+ return STATUS_SUCCESS;
+ }
+ prev = c;
+ }
+
+ /* Attach to context list */
+ iface->next = policydb->ocontexts[OCON_NETIF];
+ policydb->ocontexts[OCON_NETIF] = iface;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "error while loading interface %s", name);
+
+ if (iface != NULL) {
+ free(iface->u.name);
+ context_destroy(&iface->context[0]);
+ context_destroy(&iface->context[1]);
+ free(iface);
+ }
+ return STATUS_ERR;
+}
+
+/* Return the number of interfaces */
+extern int sepol_iface_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ return STATUS_SUCCESS;
+}
+
+int sepol_iface_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_iface_t * iface,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_iface_t *iface = NULL;
+
+ head = policydb->ocontexts[OCON_NETIF];
+ for (c = head; c; c = c->next) {
+ int status;
+
+ if (iface_to_record(handle, policydb, c, &iface) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(iface, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_iface_free(iface);
+ iface = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over interfaces");
+ sepol_iface_free(iface);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
new file mode 100644
index 0000000..0a46b09
--- /dev/null
+++ b/libsepol/src/libsepol.map.in
@@ -0,0 +1,52 @@
+LIBSEPOL_1.0 {
+ global:
+ expand_module_avrules;
+ sepol_module_package_*; sepol_link_modules; sepol_expand_module; sepol_link_packages;
+ sepol_bool_*; sepol_genbools*;
+ sepol_context_*; sepol_mls_*; sepol_check_context;
+ sepol_iface_*;
+ sepol_port_*;
+ sepol_node_*;
+ sepol_user_*; sepol_genusers; sepol_set_delusers;
+ sepol_msg_*; sepol_debug;
+ sepol_handle_*;
+ sepol_policydb_*; sepol_set_policydb_from_file;
+ sepol_policy_kern_*;
+ sepol_policy_file_*;
+ sepol_get_disable_dontaudit;
+ sepol_set_disable_dontaudit;
+ sepol_set_expand_consume_base;
+ sepol_get_preserve_tunables; sepol_set_preserve_tunables;
+ cil_db_init;
+ cil_set_disable_dontaudit;
+ cil_set_disable_neverallow;
+ cil_set_preserve_tunables;
+ cil_set_handle_unknown;
+ cil_db_destroy;
+ cil_add_file;
+ cil_compile;
+ cil_build_policydb;
+ cil_userprefixes_to_string;
+ cil_selinuxusers_to_string;
+ cil_filecons_to_string;
+ cil_set_log_level;
+ cil_set_log_handler;
+ cil_set_malloc_error_handler;
+ local: *;
+};
+
+LIBSEPOL_1.1 {
+ global:
+ cil_build_policydb;
+ cil_compile;
+ cil_userprefixes_to_string;
+ cil_selinuxusers_to_string;
+ cil_filecons_to_string;
+ cil_set_target_platform;
+ cil_set_policy_version;
+ cil_set_mls;
+ sepol_ppfile_to_module_package;
+ sepol_module_package_to_cil;
+ sepol_module_policydb_to_cil;
+ local: *;
+} LIBSEPOL_1.0;
diff --git a/libsepol/src/libsepol.pc.in b/libsepol/src/libsepol.pc.in
new file mode 100644
index 0000000..e52f589
--- /dev/null
+++ b/libsepol/src/libsepol.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@libdir@
+includedir=@includedir@
+
+Name: libsepol
+Description: SELinux policy library
+Version: @VERSION@
+URL: http://userspace.selinuxproject.org/
+Libs: -L${libdir} -lsepol
+Cflags: -I${includedir}
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
new file mode 100644
index 0000000..f211164
--- /dev/null
+++ b/libsepol/src/link.c
@@ -0,0 +1,2668 @@
+/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/util.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "debug.h"
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+typedef struct policy_module {
+ policydb_t *policy;
+ uint32_t num_decls;
+ uint32_t *map[SYM_NUM];
+ uint32_t *avdecl_map;
+ uint32_t **perm_map;
+ uint32_t *perm_map_len;
+
+ /* a pointer to within the base module's avrule_block chain to
+ * where this module's global now resides */
+ avrule_block_t *base_global;
+} policy_module_t;
+
+typedef struct link_state {
+ int verbose;
+ policydb_t *base;
+ avrule_block_t *last_avrule_block, *last_base_avrule_block;
+ uint32_t next_decl_id, current_decl_id;
+
+ /* temporary variables, used during hashtab_map() calls */
+ policy_module_t *cur;
+ char *cur_mod_name;
+ avrule_decl_t *dest_decl;
+ class_datum_t *src_class, *dest_class;
+ char *dest_class_name;
+ char dest_class_req; /* flag indicating the class was not declared */
+ uint32_t symbol_num;
+ /* used to report the name of the module if dependancy error occurs */
+ policydb_t **decl_to_mod;
+
+ /* error reporting fields */
+ sepol_handle_t *handle;
+} link_state_t;
+
+typedef struct missing_requirement {
+ uint32_t symbol_type;
+ uint32_t symbol_value;
+ uint32_t perm_value;
+} missing_requirement_t;
+
+static const char *symtab_names[SYM_NUM] = {
+ "common", "class", "role", "type/attribute", "user",
+ "bool", "level", "category"
+};
+
+/* Deallocates all elements within a module, but NOT the policydb_t
+ * structure within, as well as the pointer itself. */
+static void policy_module_destroy(policy_module_t * mod)
+{
+ unsigned int i;
+ if (mod == NULL) {
+ return;
+ }
+ for (i = 0; i < SYM_NUM; i++) {
+ free(mod->map[i]);
+ }
+ for (i = 0; mod->perm_map != NULL && i < mod->policy->p_classes.nprim;
+ i++) {
+ free(mod->perm_map[i]);
+ }
+ free(mod->perm_map);
+ free(mod->perm_map_len);
+ free(mod->avdecl_map);
+ free(mod);
+}
+
+/***** functions that copy identifiers from a module to base *****/
+
+/* Note: there is currently no scoping for permissions, which causes some
+ * strange side-effects. The current approach is this:
+ *
+ * a) perm is required and the class _and_ perm are declared in base: only add a mapping.
+ * b) perm is required and the class and perm are _not_ declared in base: simply add the permissions
+ * to the object class. This means that the requirements for the decl are the union of the permissions
+ * required for all decls, but who cares.
+ * c) perm is required, the class is declared in base, but the perm is not present. Nothing we can do
+ * here because we can't mark a single permission as required, so we bail with a requirement error
+ * _even_ if we are in an optional.
+ *
+ * A is correct behavior, b is wrong but not too bad, c is totall wrong for optionals. Fixing this requires
+ * a format change.
+ */
+static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *perm_id = key, *new_id = NULL;
+ perm_datum_t *perm, *new_perm = NULL, *dest_perm;
+ link_state_t *state = (link_state_t *) data;
+
+ class_datum_t *src_class = state->src_class;
+ class_datum_t *dest_class = state->dest_class;
+ policy_module_t *mod = state->cur;
+ uint32_t sclassi = src_class->s.value - 1;
+ int ret;
+
+ perm = (perm_datum_t *) datum;
+ dest_perm = hashtab_search(dest_class->permissions.table, perm_id);
+ if (dest_perm == NULL && dest_class->comdatum != NULL) {
+ dest_perm =
+ hashtab_search(dest_class->comdatum->permissions.table,
+ perm_id);
+ }
+
+ if (dest_perm == NULL) {
+ /* If the object class was not declared in the base, add the perm
+ * to the object class. */
+ if (state->dest_class_req) {
+ /* If the class was required (not declared), insert the new permission */
+ new_id = strdup(perm_id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Memory error");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ new_perm =
+ (perm_datum_t *) calloc(1, sizeof(perm_datum_t));
+ if (new_perm == NULL) {
+ ERR(state->handle, "Memory error");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ ret = hashtab_insert(dest_class->permissions.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_perm);
+ if (ret) {
+ ERR(state->handle,
+ "could not insert permission into class\n");
+ goto err;
+ }
+ new_perm->s.value = dest_class->permissions.nprim + 1;
+ dest_perm = new_perm;
+ } else {
+ /* this is case c from above */
+ ERR(state->handle,
+ "Module %s depends on permission %s in class %s, not satisfied",
+ state->cur_mod_name, perm_id,
+ state->dest_class_name);
+ return SEPOL_EREQ;
+ }
+ }
+
+ /* build the mapping for permissions encompassing this class.
+ * unlike symbols, the permission map translates between
+ * module permission bit to target permission bit. that bit
+ * may have originated from the class -or- it could be from
+ * the class's common parent.*/
+ if (perm->s.value > mod->perm_map_len[sclassi]) {
+ uint32_t *newmap = calloc(perm->s.value, sizeof(*newmap));
+ if (newmap == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ memcpy(newmap, mod->perm_map[sclassi],
+ mod->perm_map_len[sclassi] * sizeof(*newmap));
+ free(mod->perm_map[sclassi]);
+ mod->perm_map[sclassi] = newmap;
+ mod->perm_map_len[sclassi] = perm->s.value;
+ }
+ mod->perm_map[sclassi][perm->s.value - 1] = dest_perm->s.value;
+
+ return 0;
+ err:
+ free(new_id);
+ free(new_perm);
+ return ret;
+}
+
+static int class_copy_default_new_object(link_state_t *state,
+ class_datum_t *olddatum,
+ class_datum_t *newdatum)
+{
+ if (olddatum->default_user) {
+ if (newdatum->default_user && olddatum->default_user != newdatum->default_user) {
+ ERR(state->handle, "Found conflicting default user definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_user = olddatum->default_user;
+ }
+ if (olddatum->default_role) {
+ if (newdatum->default_role && olddatum->default_role != newdatum->default_role) {
+ ERR(state->handle, "Found conflicting default role definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_role = olddatum->default_role;
+ }
+ if (olddatum->default_type) {
+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
+ ERR(state->handle, "Found conflicting default type definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_type = olddatum->default_type;
+ }
+ if (olddatum->default_range) {
+ if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
+ ERR(state->handle, "Found conflicting default range definitions");
+ return SEPOL_ENOTSUP;
+ }
+ newdatum->default_range = olddatum->default_range;
+ }
+ return 0;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key, *new_id = NULL;
+ class_datum_t *cladatum, *new_class = NULL;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope = NULL;
+ int ret;
+
+ cladatum = (class_datum_t *) datum;
+ state->dest_class_req = 0;
+
+ new_class = hashtab_search(state->base->p_classes.table, id);
+ /* If there is not an object class already in the base symtab that means
+ * that either a) a module is trying to declare a new object class (which
+ * the compiler should prevent) or b) an object class was required that is
+ * not in the base.
+ */
+ if (new_class == NULL) {
+ scope =
+ hashtab_search(state->cur->policy->p_classes_scope.table,
+ id);
+ if (scope == NULL) {
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not yet declare new classes.",
+ state->cur_mod_name);
+ ret = SEPOL_ENOTSUP;
+ goto err;
+ } else {
+ /* It would be nice to error early here because the requirement is
+ * not met, but we cannot because the decl might be optional (in which
+ * case we should record the requirement so that it is just turned
+ * off). Note: this will break horribly if modules can declare object
+ * classes because the class numbers will be all wrong (i.e., they
+ * might be assigned in the order they were required rather than the
+ * current scheme which ensures correct numbering by ordering the
+ * declarations properly). This can't be fixed until some infrastructure
+ * for querying the object class numbers is in place. */
+ state->dest_class_req = 1;
+ new_class =
+ (class_datum_t *) calloc(1, sizeof(class_datum_t));
+ if (new_class == NULL) {
+ ERR(state->handle, "Memory error\n");
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ if (symtab_init
+ (&new_class->permissions, PERM_SYMTAB_SIZE)) {
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ new_id = strdup(id);
+ if (new_id == NULL) {
+ ERR(state->handle, "Memory error\n");
+ symtab_destroy(&new_class->permissions);
+ ret = SEPOL_ERR;
+ goto err;
+ }
+ ret = hashtab_insert(state->base->p_classes.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_class);
+ if (ret) {
+ ERR(state->handle,
+ "could not insert new class into symtab");
+ symtab_destroy(&new_class->permissions);
+ goto err;
+ }
+ new_class->s.value = ++(state->base->p_classes.nprim);
+ }
+ }
+
+ state->cur->map[SYM_CLASSES][cladatum->s.value - 1] =
+ new_class->s.value;
+
+ /* copy permissions */
+ state->src_class = cladatum;
+ state->dest_class = new_class;
+ state->dest_class_name = (char *)key;
+
+ /* copy default new object rules */
+ ret = class_copy_default_new_object(state, cladatum, new_class);
+ if (ret)
+ return ret;
+
+ ret =
+ hashtab_map(cladatum->permissions.table, permission_copy_callback,
+ state);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+ err:
+ free(new_class);
+ free(new_id);
+ return ret;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ role_datum_t *role, *base_role, *new_role = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ role = (role_datum_t *) datum;
+
+ base_role = hashtab_search(state->base->p_roles.table, id);
+ if (base_role != NULL) {
+ /* role already exists. check that it is what this
+ * module expected. duplicate declarations (e.g., two
+ * modules both declare role foo_r) is checked during
+ * scope_copy_callback(). */
+ if (role->flavor == ROLE_ATTRIB
+ && base_role->flavor != ROLE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a role attribute, but it was already declared as a regular role.",
+ state->cur_mod_name, id);
+ return -1;
+ } else if (role->flavor != ROLE_ATTRIB
+ && base_role->flavor == ROLE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a regular role, but it was already declared as a role attribute.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+ } else {
+ if (state->verbose)
+ INFO(state->handle, "copying role %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_role =
+ (role_datum_t *) malloc(sizeof(*new_role))) == NULL) {
+ goto cleanup;
+ }
+ role_datum_init(new_role);
+
+ /* new_role's dominates, types and roles field will be copied
+ * during role_fix_callback() */
+ new_role->flavor = role->flavor;
+ new_role->s.value = state->base->p_roles.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_roles.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_role);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_roles.nprim++;
+ base_role = new_role;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_role = malloc(sizeof(*new_role))) == NULL) {
+ goto cleanup;
+ }
+ role_datum_init(new_role);
+ new_role->flavor = base_role->flavor;
+ new_role->s.value = base_role->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_roles.table, new_id, new_role)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_roles.nprim++;
+ }
+
+ state->cur->map[SYM_ROLES][role->s.value - 1] = base_role->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_datum_destroy(new_role);
+ free(new_id);
+ free(new_role);
+ return -1;
+}
+
+/* Copy types and attributes from a module into the base module. The
+ * attributes are copied, but the types that make up this attribute
+ * are delayed type_fix_callback(). */
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ type_datum_t *type, *base_type, *new_type = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ type = (type_datum_t *) datum;
+ if ((type->flavor == TYPE_TYPE && !type->primary)
+ || type->flavor == TYPE_ALIAS) {
+ /* aliases are handled later, in alias_copy_callback() */
+ return 0;
+ }
+
+ base_type = hashtab_search(state->base->p_types.table, id);
+ if (base_type != NULL) {
+ /* type already exists. check that it is what this
+ * module expected. duplicate declarations (e.g., two
+ * modules both declare type foo_t) is checked during
+ * scope_copy_callback(). */
+ if (type->flavor == TYPE_ATTRIB
+ && base_type->flavor != TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be an attribute, but it was already declared as a type.",
+ state->cur_mod_name, id);
+ return -1;
+ } else if (type->flavor != TYPE_ATTRIB
+ && base_type->flavor == TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s: Expected %s to be a type, but it was already declared as an attribute.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+ /* permissive should pass to the base type */
+ base_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+ } else {
+ if (state->verbose)
+ INFO(state->handle, "copying type %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_type =
+ (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ new_type->primary = type->primary;
+ new_type->flags = type->flags;
+ new_type->flavor = type->flavor;
+ /* for attributes, the writing of new_type->types is
+ done in type_fix_callback() */
+
+ new_type->s.value = state->base->p_types.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_types.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_type);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_types.nprim++;
+ base_type = new_type;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_type = calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ new_type->primary = type->primary;
+ new_type->flavor = type->flavor;
+ new_type->flags = type->flags;
+ new_type->s.value = base_type->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_types.table, new_id, new_type)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_types.nprim++;
+ }
+
+ state->cur->map[SYM_TYPES][type->s.value - 1] = base_type->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ free(new_type);
+ return -1;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ user_datum_t *user, *base_user, *new_user = NULL;
+ link_state_t *state = (link_state_t *) data;
+
+ user = (user_datum_t *) datum;
+
+ base_user = hashtab_search(state->base->p_users.table, id);
+ if (base_user == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying user %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_user =
+ (user_datum_t *) malloc(sizeof(*new_user))) == NULL) {
+ goto cleanup;
+ }
+ user_datum_init(new_user);
+ /* new_users's roles and MLS fields will be copied during
+ user_fix_callback(). */
+
+ new_user->s.value = state->base->p_users.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_users.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_user);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_users.nprim++;
+ base_user = new_user;
+ }
+
+ if (state->dest_decl) {
+ new_id = NULL;
+ if ((new_user = malloc(sizeof(*new_user))) == NULL) {
+ goto cleanup;
+ }
+ user_datum_init(new_user);
+ new_user->s.value = base_user->s.value;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->dest_decl->p_users.table, new_id, new_user)) {
+ goto cleanup;
+ }
+ state->dest_decl->p_users.nprim++;
+ }
+
+ state->cur->map[SYM_USERS][user->s.value - 1] = base_user->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ user_datum_destroy(new_user);
+ free(new_id);
+ free(new_user);
+ return -1;
+}
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ int ret;
+ char *id = key, *new_id = NULL;
+ cond_bool_datum_t *booldatum, *base_bool, *new_bool = NULL;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ booldatum = (cond_bool_datum_t *) datum;
+
+ base_bool = hashtab_search(state->base->p_bools.table, id);
+ if (base_bool == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying boolean %s", id);
+
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_bool =
+ (cond_bool_datum_t *) malloc(sizeof(*new_bool))) == NULL) {
+ goto cleanup;
+ }
+ new_bool->s.value = state->base->p_bools.nprim + 1;
+
+ ret = hashtab_insert(state->base->p_bools.table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_bool);
+ if (ret) {
+ goto cleanup;
+ }
+ state->base->p_bools.nprim++;
+ base_bool = new_bool;
+ base_bool->flags = booldatum->flags;
+ base_bool->state = booldatum->state;
+ } else if ((booldatum->flags & COND_BOOL_FLAGS_TUNABLE) !=
+ (base_bool->flags & COND_BOOL_FLAGS_TUNABLE)) {
+ /* A mismatch between boolean/tunable declaration
+ * and usage(for example a boolean used in the
+ * tunable_policy() or vice versa).
+ *
+ * This is not allowed and bail out with errors */
+ ERR(state->handle,
+ "%s: Mismatch between boolean/tunable definition "
+ "and usage for %s", state->cur_mod_name, id);
+ return -1;
+ }
+
+ /* Get the scope info for this boolean to see if this is the declaration,
+ * if so set the state */
+ scope = hashtab_search(state->cur->policy->p_bools_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL) {
+ base_bool->state = booldatum->state;
+ /* Only the declaration rather than requirement
+ * decides if it is a boolean or tunable. */
+ base_bool->flags = booldatum->flags;
+ }
+ state->cur->map[SYM_BOOLS][booldatum->s.value - 1] = base_bool->s.value;
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ cond_destroy_bool(new_id, new_bool, NULL);
+ return -1;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ level_datum_t *level, *base_level;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ level = (level_datum_t *) datum;
+
+ base_level = hashtab_search(state->base->p_levels.table, id);
+ if (!base_level) {
+ scope =
+ hashtab_search(state->cur->policy->p_sens_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not declare new sensitivities.",
+ state->cur_mod_name);
+ return SEPOL_ENOTSUP;
+ } else if (scope->scope == SCOPE_REQ) {
+ /* unmet requirement */
+ ERR(state->handle,
+ "%s: Sensitivity %s not declared by base.",
+ state->cur_mod_name, id);
+ return SEPOL_ENOTSUP;
+ } else {
+ ERR(state->handle,
+ "%s: has an unknown scope: %d\n",
+ state->cur_mod_name, scope->scope);
+ return SEPOL_ENOTSUP;
+ }
+ }
+
+ state->cur->map[SYM_LEVELS][level->level->sens - 1] =
+ base_level->level->sens;
+
+ return 0;
+}
+
+static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ cat_datum_t *cat, *base_cat;
+ link_state_t *state = (link_state_t *) data;
+ scope_datum_t *scope;
+
+ cat = (cat_datum_t *) datum;
+
+ base_cat = hashtab_search(state->base->p_cats.table, id);
+ if (!base_cat) {
+ scope = hashtab_search(state->cur->policy->p_cat_scope.table, id);
+ if (!scope)
+ return SEPOL_ERR;
+ if (scope->scope == SCOPE_DECL) {
+ /* disallow declarations in modules */
+ ERR(state->handle,
+ "%s: Modules may not declare new categories.",
+ state->cur_mod_name);
+ return SEPOL_ENOTSUP;
+ } else if (scope->scope == SCOPE_REQ) {
+ /* unmet requirement */
+ ERR(state->handle,
+ "%s: Category %s not declared by base.",
+ state->cur_mod_name, id);
+ return SEPOL_ENOTSUP;
+ } else {
+ /* unknown scope? malformed policy? */
+ ERR(state->handle,
+ "%s: has an unknown scope: %d\n",
+ state->cur_mod_name, scope->scope);
+ return SEPOL_ENOTSUP;
+ }
+ }
+
+ state->cur->map[SYM_CATS][cat->s.value - 1] = base_cat->s.value;
+
+ return 0;
+}
+
+static int (*copy_callback_f[SYM_NUM]) (hashtab_key_t key,
+ hashtab_datum_t datum, void *datap) = {
+NULL, class_copy_callback, role_copy_callback, type_copy_callback,
+ user_copy_callback, bool_copy_callback, sens_copy_callback,
+ cat_copy_callback};
+
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ type_datum_t *type = (type_datum_t *) datum;
+ type_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!type->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_TYPES][type->bounds - 1];
+
+ dest = hashtab_search(state->base->p_types.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "Type lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ role_datum_t *role = (role_datum_t *) datum;
+ role_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!role->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_ROLES][role->bounds - 1];
+
+ dest = hashtab_search(state->base->p_roles.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "Role lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+ hashtab_datum_t datum, void *data)
+{
+ link_state_t *state = (link_state_t *) data;
+ user_datum_t *user = (user_datum_t *) datum;
+ user_datum_t *dest;
+ uint32_t bounds_val;
+
+ if (!user->bounds)
+ return 0;
+
+ bounds_val = state->cur->map[SYM_USERS][user->bounds - 1];
+
+ dest = hashtab_search(state->base->p_users.table, key);
+ if (!dest) {
+ ERR(state->handle,
+ "User lookup failed for %s", (char *)key);
+ return -1;
+ }
+ if (dest->bounds != 0 && dest->bounds != bounds_val) {
+ ERR(state->handle,
+ "Inconsistent boundary for %s", (char *)key);
+ return -1;
+ }
+ dest->bounds = bounds_val;
+
+ return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be
+ * certain that the base symbol table will have the type that the
+ * alias refers. Otherwise, we won't be able to find the type value
+ * for the alias. We can't depend on the declaration ordering because
+ * of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key, *new_id = NULL, *target_id;
+ type_datum_t *type, *base_type, *new_type = NULL, *target_type;
+ link_state_t *state = (link_state_t *) data;
+ policy_module_t *mod = state->cur;
+ int primval;
+
+ type = (type_datum_t *) datum;
+ /* there are 2 kinds of aliases. Ones with their own value (TYPE_ALIAS)
+ * and ones with the value of their primary (TYPE_TYPE && type->primary = 0)
+ */
+ if (!
+ (type->flavor == TYPE_ALIAS
+ || (type->flavor == TYPE_TYPE && !type->primary))) {
+ /* ignore types and attributes -- they were handled in
+ * type_copy_callback() */
+ return 0;
+ }
+
+ if (type->flavor == TYPE_ALIAS)
+ primval = type->primary;
+ else
+ primval = type->s.value;
+
+ target_id = mod->policy->p_type_val_to_name[primval - 1];
+ target_type = hashtab_search(state->base->p_types.table, target_id);
+ if (target_type == NULL) {
+ ERR(state->handle, "%s: Could not find type %s for alias %s.",
+ state->cur_mod_name, target_id, id);
+ return -1;
+ }
+
+ if (!strcmp(id, target_id)) {
+ ERR(state->handle, "%s: Self aliasing of %s.",
+ state->cur_mod_name, id);
+ return -1;
+ }
+
+ target_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE);
+
+ base_type = hashtab_search(state->base->p_types.table, id);
+ if (base_type == NULL) {
+ if (state->verbose)
+ INFO(state->handle, "copying alias %s", id);
+
+ if ((new_type =
+ (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) {
+ goto cleanup;
+ }
+ /* the linked copy always has TYPE_ALIAS style aliases */
+ new_type->primary = target_type->s.value;
+ new_type->flags = target_type->flags;
+ new_type->flavor = TYPE_ALIAS;
+ new_type->s.value = state->base->p_types.nprim + 1;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+ if (hashtab_insert
+ (state->base->p_types.table, new_id, new_type)) {
+ goto cleanup;
+ }
+ state->base->p_types.nprim++;
+ base_type = new_type;
+ } else {
+
+ /* if this already exists and isn't an alias it was required by another module (or base)
+ * and inserted into the hashtable as a type, fix it up now */
+
+ if (base_type->flavor == TYPE_ALIAS) {
+ /* error checking */
+ assert(base_type->primary == target_type->s.value);
+ assert(base_type->primary ==
+ mod->map[SYM_TYPES][primval - 1]);
+ assert(mod->map[SYM_TYPES][type->s.value - 1] ==
+ base_type->primary);
+ return 0;
+ }
+
+ if (base_type->flavor == TYPE_ATTRIB) {
+ ERR(state->handle,
+ "%s is an alias of an attribute, not allowed", id);
+ return -1;
+ }
+
+ base_type->flavor = TYPE_ALIAS;
+ base_type->primary = target_type->s.value;
+ base_type->flags |= (target_type->flags & TYPE_FLAGS_PERMISSIVE);
+
+ }
+ /* the aliases map points from its value to its primary so when this module
+ * references this type the value it gets back from the map is the primary */
+ mod->map[SYM_TYPES][type->s.value - 1] = base_type->primary;
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ free(new_id);
+ free(new_type);
+ return -1;
+}
+
+/*********** callbacks that fix bitmaps ***********/
+
+static int type_set_convert(type_set_t * types, type_set_t * dst,
+ policy_module_t * mod, link_state_t * state
+ __attribute__ ((unused)))
+{
+ unsigned int i;
+ ebitmap_node_t *tnode;
+ ebitmap_for_each_bit(&types->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&dst->types, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ ebitmap_for_each_bit(&types->negset, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&dst->negset, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ dst->flags = types->flags;
+ return 0;
+
+ cleanup:
+ return -1;
+}
+
+/* OR 2 typemaps together and at the same time map the src types to
+ * the correct values in the dst typeset.
+ */
+static int type_set_or_convert(type_set_t * types, type_set_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ type_set_t ts_tmp;
+
+ type_set_init(&ts_tmp);
+ if (type_set_convert(types, &ts_tmp, mod, state) == -1) {
+ goto cleanup;
+ }
+ if (type_set_or_eq(dst, &ts_tmp)) {
+ goto cleanup;
+ }
+ type_set_destroy(&ts_tmp);
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ type_set_destroy(&ts_tmp);
+ return -1;
+}
+
+static int role_set_or_convert(role_set_t * roles, role_set_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ unsigned int i;
+ ebitmap_t tmp;
+ ebitmap_node_t *rnode;
+
+ ebitmap_init(&tmp);
+ ebitmap_for_each_bit(&roles->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dst->roles, &tmp)) {
+ goto cleanup;
+ }
+ dst->flags |= roles->flags;
+ ebitmap_destroy(&tmp);
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&tmp);
+ return -1;
+}
+
+static int mls_level_convert(mls_semantic_level_t * src, mls_semantic_level_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ mls_semantic_cat_t *src_cat, *new_cat;
+
+ if (!mod->policy->mls)
+ return 0;
+
+ /* Required not declared. */
+ if (!src->sens)
+ return 0;
+
+ assert(mod->map[SYM_LEVELS][src->sens - 1]);
+ dst->sens = mod->map[SYM_LEVELS][src->sens - 1];
+
+ for (src_cat = src->cat; src_cat; src_cat = src_cat->next) {
+ new_cat =
+ (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!new_cat) {
+ ERR(state->handle, "Out of memory");
+ return -1;
+ }
+ mls_semantic_cat_init(new_cat);
+
+ new_cat->next = dst->cat;
+ dst->cat = new_cat;
+
+ assert(mod->map[SYM_CATS][src_cat->low - 1]);
+ dst->cat->low = mod->map[SYM_CATS][src_cat->low - 1];
+ assert(mod->map[SYM_CATS][src_cat->high - 1]);
+ dst->cat->high = mod->map[SYM_CATS][src_cat->high - 1];
+ }
+
+ return 0;
+}
+
+static int mls_range_convert(mls_semantic_range_t * src, mls_semantic_range_t * dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ int ret;
+ ret = mls_level_convert(&src->level[0], &dst->level[0], mod, state);
+ if (ret)
+ return ret;
+ ret = mls_level_convert(&src->level[1], &dst->level[1], mod, state);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ char *id = key;
+ role_datum_t *role, *dest_role = NULL;
+ link_state_t *state = (link_state_t *) data;
+ ebitmap_t e_tmp;
+ policy_module_t *mod = state->cur;
+ ebitmap_node_t *rnode;
+ hashtab_t role_tab;
+
+ role = (role_datum_t *) datum;
+ if (state->dest_decl == NULL)
+ role_tab = state->base->p_roles.table;
+ else
+ role_tab = state->dest_decl->p_roles.table;
+
+ dest_role = hashtab_search(role_tab, id);
+ assert(dest_role != NULL);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing role %s", id);
+ }
+
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&role->dominates, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dest_role->dominates, &e_tmp)) {
+ goto cleanup;
+ }
+ if (type_set_or_convert(&role->types, &dest_role->types, mod, state)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+
+ if (role->flavor == ROLE_ATTRIB) {
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ assert(mod->map[SYM_ROLES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&dest_role->roles, &e_tmp)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+ }
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&e_tmp);
+ return -1;
+}
+
+static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ char *id = key;
+ type_datum_t *type, *new_type = NULL;
+ link_state_t *state = (link_state_t *) data;
+ ebitmap_t e_tmp;
+ policy_module_t *mod = state->cur;
+ ebitmap_node_t *tnode;
+ symtab_t *typetab;
+
+ type = (type_datum_t *) datum;
+
+ if (state->dest_decl == NULL)
+ typetab = &state->base->p_types;
+ else
+ typetab = &state->dest_decl->p_types;
+
+ /* only fix attributes */
+ if (type->flavor != TYPE_ATTRIB) {
+ return 0;
+ }
+
+ new_type = hashtab_search(typetab->table, id);
+ assert(new_type != NULL && new_type->flavor == TYPE_ATTRIB);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing attribute %s", id);
+ }
+
+ ebitmap_init(&e_tmp);
+ ebitmap_for_each_bit(&type->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ assert(mod->map[SYM_TYPES][i]);
+ if (ebitmap_set_bit
+ (&e_tmp, mod->map[SYM_TYPES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+ if (ebitmap_union(&new_type->types, &e_tmp)) {
+ goto cleanup;
+ }
+ ebitmap_destroy(&e_tmp);
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ ebitmap_destroy(&e_tmp);
+ return -1;
+}
+
+static int user_fix_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ user_datum_t *user, *new_user = NULL;
+ link_state_t *state = (link_state_t *) data;
+ policy_module_t *mod = state->cur;
+ symtab_t *usertab;
+
+ user = (user_datum_t *) datum;
+
+ if (state->dest_decl == NULL)
+ usertab = &state->base->p_users;
+ else
+ usertab = &state->dest_decl->p_users;
+
+ new_user = hashtab_search(usertab->table, id);
+ assert(new_user != NULL);
+
+ if (state->verbose) {
+ INFO(state->handle, "fixing user %s", id);
+ }
+
+ if (role_set_or_convert(&user->roles, &new_user->roles, mod, state)) {
+ goto cleanup;
+ }
+
+ if (mls_range_convert(&user->range, &new_user->range, mod, state))
+ goto cleanup;
+
+ if (mls_level_convert(&user->dfltlevel, &new_user->dfltlevel, mod, state))
+ goto cleanup;
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int (*fix_callback_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+NULL, NULL, role_fix_callback, type_fix_callback, user_fix_callback,
+ NULL, NULL, NULL};
+
+/*********** functions that copy AV rules ***********/
+
+static int copy_avrule_list(avrule_t * list, avrule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned int i;
+ avrule_t *cur, *new_rule = NULL, *tail;
+ class_perm_node_t *cur_perm, *new_perm, *tail_perm = NULL;
+
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+
+ cur = list;
+ while (cur) {
+ if ((new_rule = (avrule_t *) malloc(sizeof(avrule_t))) == NULL) {
+ goto cleanup;
+ }
+ avrule_init(new_rule);
+
+ new_rule->specified = cur->specified;
+ new_rule->flags = cur->flags;
+ if (type_set_convert
+ (&cur->stypes, &new_rule->stypes, module, state) == -1
+ || type_set_convert(&cur->ttypes, &new_rule->ttypes, module,
+ state) == -1) {
+ goto cleanup;
+ }
+
+ cur_perm = cur->perms;
+ tail_perm = NULL;
+ while (cur_perm) {
+ if ((new_perm = (class_perm_node_t *)
+ malloc(sizeof(class_perm_node_t))) == NULL) {
+ goto cleanup;
+ }
+ class_perm_node_init(new_perm);
+
+ new_perm->tclass =
+ module->map[SYM_CLASSES][cur_perm->tclass - 1];
+ assert(new_perm->tclass);
+
+ if (new_rule->specified & AVRULE_AV) {
+ for (i = 0;
+ i <
+ module->perm_map_len[cur_perm->tclass - 1];
+ i++) {
+ if (!(cur_perm->data & (1U << i)))
+ continue;
+ new_perm->data |=
+ (1U <<
+ (module->
+ perm_map[cur_perm->tclass - 1][i] -
+ 1));
+ }
+ } else {
+ new_perm->data =
+ module->map[SYM_TYPES][cur_perm->data - 1];
+ }
+
+ if (new_rule->perms == NULL) {
+ new_rule->perms = new_perm;
+ } else {
+ assert(tail_perm);
+ tail_perm->next = new_perm;
+ }
+ tail_perm = new_perm;
+ cur_perm = cur_perm->next;
+ }
+ new_rule->line = cur->line;
+ new_rule->source_line = cur->source_line;
+ if (cur->source_filename) {
+ new_rule->source_filename = strdup(cur->source_filename);
+ if (!new_rule->source_filename)
+ goto cleanup;
+ }
+
+ cur = cur->next;
+
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ }
+
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ avrule_destroy(new_rule);
+ free(new_rule);
+ return -1;
+}
+
+static int copy_role_trans_list(role_trans_rule_t * list,
+ role_trans_rule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ role_trans_rule_t *cur, *new_rule = NULL, *tail;
+ unsigned int i;
+ ebitmap_node_t *cnode;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+ while (cur) {
+ if ((new_rule =
+ (role_trans_rule_t *) malloc(sizeof(role_trans_rule_t))) ==
+ NULL) {
+ goto cleanup;
+ }
+ role_trans_rule_init(new_rule);
+
+ if (role_set_or_convert
+ (&cur->roles, &new_rule->roles, module, state)
+ || type_set_or_convert(&cur->types, &new_rule->types,
+ module, state)) {
+ goto cleanup;
+ }
+
+ ebitmap_for_each_bit(&cur->classes, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ assert(module->map[SYM_CLASSES][i]);
+ if (ebitmap_set_bit(&new_rule->classes,
+ module->
+ map[SYM_CLASSES][i] - 1,
+ 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ new_rule->new_role = module->map[SYM_ROLES][cur->new_role - 1];
+
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_trans_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_role_allow_list(role_allow_rule_t * list,
+ role_allow_rule_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ role_allow_rule_t *cur, *new_rule = NULL, *tail;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next) {
+ tail = tail->next;
+ }
+
+ while (cur) {
+ if ((new_rule =
+ (role_allow_rule_t *) malloc(sizeof(role_allow_rule_t))) ==
+ NULL) {
+ goto cleanup;
+ }
+ role_allow_rule_init(new_rule);
+
+ if (role_set_or_convert
+ (&cur->roles, &new_rule->roles, module, state)
+ || role_set_or_convert(&cur->new_roles,
+ &new_rule->new_roles, module,
+ state)) {
+ goto cleanup;
+ }
+ if (*dst == NULL) {
+ *dst = new_rule;
+ } else {
+ tail->next = new_rule;
+ }
+ tail = new_rule;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ role_allow_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_filename_trans_list(filename_trans_rule_t * list,
+ filename_trans_rule_t ** dst,
+ policy_module_t * module,
+ link_state_t * state)
+{
+ filename_trans_rule_t *cur, *new_rule, *tail;
+
+ cur = list;
+ tail = *dst;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ while (cur) {
+ new_rule = malloc(sizeof(*new_rule));
+ if (!new_rule)
+ goto err;
+
+ filename_trans_rule_init(new_rule);
+
+ if (*dst == NULL)
+ *dst = new_rule;
+ else
+ tail->next = new_rule;
+ tail = new_rule;
+
+ new_rule->name = strdup(cur->name);
+ if (!new_rule->name)
+ goto err;
+
+ if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module, state) ||
+ type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module, state))
+ goto err;
+
+ new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1];
+ new_rule->otype = module->map[SYM_TYPES][cur->otype - 1];
+
+ cur = cur->next;
+ }
+ return 0;
+err:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int copy_range_trans_list(range_trans_rule_t * rules,
+ range_trans_rule_t ** dst,
+ policy_module_t * mod, link_state_t * state)
+{
+ range_trans_rule_t *rule, *new_rule = NULL;
+ unsigned int i;
+ ebitmap_node_t *cnode;
+
+ for (rule = rules; rule; rule = rule->next) {
+ new_rule =
+ (range_trans_rule_t *) malloc(sizeof(range_trans_rule_t));
+ if (!new_rule)
+ goto cleanup;
+
+ range_trans_rule_init(new_rule);
+
+ new_rule->next = *dst;
+ *dst = new_rule;
+
+ if (type_set_convert(&rule->stypes, &new_rule->stypes,
+ mod, state))
+ goto cleanup;
+
+ if (type_set_convert(&rule->ttypes, &new_rule->ttypes,
+ mod, state))
+ goto cleanup;
+
+ ebitmap_for_each_bit(&rule->tclasses, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ assert(mod->map[SYM_CLASSES][i]);
+ if (ebitmap_set_bit
+ (&new_rule->tclasses,
+ mod->map[SYM_CLASSES][i] - 1, 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ if (mls_range_convert(&rule->trange, &new_rule->trange, mod, state))
+ goto cleanup;
+ }
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ range_trans_rule_list_destroy(new_rule);
+ return -1;
+}
+
+static int copy_cond_list(cond_node_t * list, cond_node_t ** dst,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned i;
+ cond_node_t *cur, *new_node = NULL, *tail;
+ cond_expr_t *cur_expr;
+ tail = *dst;
+ while (tail && tail->next)
+ tail = tail->next;
+
+ cur = list;
+ while (cur) {
+ new_node = (cond_node_t *) malloc(sizeof(cond_node_t));
+ if (!new_node) {
+ goto cleanup;
+ }
+ memset(new_node, 0, sizeof(cond_node_t));
+
+ new_node->cur_state = cur->cur_state;
+ new_node->expr = cond_copy_expr(cur->expr);
+ if (!new_node->expr)
+ goto cleanup;
+ /* go back through and remap the expression */
+ for (cur_expr = new_node->expr; cur_expr != NULL;
+ cur_expr = cur_expr->next) {
+ /* expression nodes don't have a bool value of 0 - don't map them */
+ if (cur_expr->expr_type != COND_BOOL)
+ continue;
+ assert(module->map[SYM_BOOLS][cur_expr->bool - 1] != 0);
+ cur_expr->bool =
+ module->map[SYM_BOOLS][cur_expr->bool - 1];
+ }
+ new_node->nbools = cur->nbools;
+ /* FIXME should COND_MAX_BOOLS be used here? */
+ for (i = 0; i < min(cur->nbools, COND_MAX_BOOLS); i++) {
+ uint32_t remapped_id =
+ module->map[SYM_BOOLS][cur->bool_ids[i] - 1];
+ assert(remapped_id != 0);
+ new_node->bool_ids[i] = remapped_id;
+ }
+ new_node->expr_pre_comp = cur->expr_pre_comp;
+
+ if (copy_avrule_list
+ (cur->avtrue_list, &new_node->avtrue_list, module, state)
+ || copy_avrule_list(cur->avfalse_list,
+ &new_node->avfalse_list, module,
+ state)) {
+ goto cleanup;
+ }
+
+ if (*dst == NULL) {
+ *dst = new_node;
+ } else {
+ tail->next = new_node;
+ }
+ tail = new_node;
+ cur = cur->next;
+ }
+ return 0;
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ cond_node_destroy(new_node);
+ free(new_node);
+ return -1;
+
+}
+
+/*********** functions that copy avrule_decls from module to base ***********/
+
+static int copy_identifiers(link_state_t * state, symtab_t * src_symtab,
+ avrule_decl_t * dest_decl)
+{
+ int i, ret;
+
+ state->dest_decl = dest_decl;
+ for (i = 0; i < SYM_NUM; i++) {
+ if (copy_callback_f[i] != NULL) {
+ ret =
+ hashtab_map(src_symtab[i].table, copy_callback_f[i],
+ state);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+
+ if (hashtab_map(src_symtab[SYM_TYPES].table,
+ type_bounds_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_TYPES].table,
+ alias_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_ROLES].table,
+ role_bounds_copy_callback, state))
+ return -1;
+
+ if (hashtab_map(src_symtab[SYM_USERS].table,
+ user_bounds_copy_callback, state))
+ return -1;
+
+ /* then fix bitmaps associated with those newly copied identifiers */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (fix_callback_f[i] != NULL &&
+ hashtab_map(src_symtab[i].table, fix_callback_f[i],
+ state)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int copy_scope_index(scope_index_t * src, scope_index_t * dest,
+ policy_module_t * module, link_state_t * state)
+{
+ unsigned int i, j;
+ uint32_t largest_mapped_class_value = 0;
+ ebitmap_node_t *node;
+ /* copy the scoping information for this avrule decl block */
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_t *srcmap = src->scope + i;
+ ebitmap_t *destmap = dest->scope + i;
+ if (copy_callback_f[i] == NULL) {
+ continue;
+ }
+ ebitmap_for_each_bit(srcmap, node, j) {
+ if (ebitmap_node_get_bit(node, j)) {
+ assert(module->map[i][j] != 0);
+ if (ebitmap_set_bit
+ (destmap, module->map[i][j] - 1, 1) != 0) {
+
+ goto cleanup;
+ }
+ if (i == SYM_CLASSES &&
+ largest_mapped_class_value <
+ module->map[SYM_CLASSES][j]) {
+ largest_mapped_class_value =
+ module->map[SYM_CLASSES][j];
+ }
+ }
+ }
+ }
+
+ /* next copy the enabled permissions data */
+ if ((dest->class_perms_map = malloc(largest_mapped_class_value *
+ sizeof(*dest->class_perms_map))) ==
+ NULL) {
+ goto cleanup;
+ }
+ for (i = 0; i < largest_mapped_class_value; i++) {
+ ebitmap_init(dest->class_perms_map + i);
+ }
+ dest->class_perms_len = largest_mapped_class_value;
+ for (i = 0; i < src->class_perms_len; i++) {
+ ebitmap_t *srcmap = src->class_perms_map + i;
+ ebitmap_t *destmap =
+ dest->class_perms_map + module->map[SYM_CLASSES][i] - 1;
+ ebitmap_for_each_bit(srcmap, node, j) {
+ if (ebitmap_node_get_bit(node, j) &&
+ ebitmap_set_bit(destmap, module->perm_map[i][j] - 1,
+ 1)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+static int copy_avrule_decl(link_state_t * state, policy_module_t * module,
+ avrule_decl_t * src_decl, avrule_decl_t * dest_decl)
+{
+ int ret;
+
+ /* copy all of the RBAC and TE rules */
+ if (copy_avrule_list
+ (src_decl->avrules, &dest_decl->avrules, module, state) == -1
+ || copy_role_trans_list(src_decl->role_tr_rules,
+ &dest_decl->role_tr_rules, module,
+ state) == -1
+ || copy_role_allow_list(src_decl->role_allow_rules,
+ &dest_decl->role_allow_rules, module,
+ state) == -1
+ || copy_cond_list(src_decl->cond_list, &dest_decl->cond_list,
+ module, state) == -1) {
+ return -1;
+ }
+
+ if (copy_filename_trans_list(src_decl->filename_trans_rules,
+ &dest_decl->filename_trans_rules,
+ module, state))
+ return -1;
+
+ if (copy_range_trans_list(src_decl->range_tr_rules,
+ &dest_decl->range_tr_rules, module, state))
+ return -1;
+
+ /* finally copy any identifiers local to this declaration */
+ ret = copy_identifiers(state, src_decl->symtab, dest_decl);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* then copy required and declared scope indices here */
+ if (copy_scope_index(&src_decl->required, &dest_decl->required,
+ module, state) == -1 ||
+ copy_scope_index(&src_decl->declared, &dest_decl->declared,
+ module, state) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int copy_avrule_block(link_state_t * state, policy_module_t * module,
+ avrule_block_t * block)
+{
+ avrule_block_t *new_block = avrule_block_create();
+ avrule_decl_t *decl, *last_decl = NULL;
+ int ret;
+
+ if (new_block == NULL) {
+ ERR(state->handle, "Out of memory!");
+ ret = -1;
+ goto cleanup;
+ }
+
+ new_block->flags = block->flags;
+
+ for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+ avrule_decl_t *new_decl =
+ avrule_decl_create(state->next_decl_id);
+ if (new_decl == NULL) {
+ ERR(state->handle, "Out of memory!");
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (module->policy->name != NULL) {
+ new_decl->module_name = strdup(module->policy->name);
+ if (new_decl->module_name == NULL) {
+ ERR(state->handle, "Out of memory\n");
+ avrule_decl_destroy(new_decl);
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ if (last_decl == NULL) {
+ new_block->branch_list = new_decl;
+ } else {
+ last_decl->next = new_decl;
+ }
+ last_decl = new_decl;
+ state->base->decl_val_to_struct[state->next_decl_id - 1] =
+ new_decl;
+ state->decl_to_mod[state->next_decl_id] = module->policy;
+
+ module->avdecl_map[decl->decl_id] = new_decl->decl_id;
+
+ ret = copy_avrule_decl(state, module, decl, new_decl);
+ if (ret) {
+ avrule_decl_destroy(new_decl);
+ goto cleanup;
+ }
+
+ state->next_decl_id++;
+ }
+ state->last_avrule_block->next = new_block;
+ state->last_avrule_block = new_block;
+ return 0;
+
+ cleanup:
+ avrule_block_list_destroy(new_block);
+ return ret;
+}
+
+static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
+ void *data)
+{
+ unsigned int i;
+ int ret;
+ char *id = key, *new_id = NULL;
+ scope_datum_t *scope, *base_scope;
+ link_state_t *state = (link_state_t *) data;
+ uint32_t symbol_num = state->symbol_num;
+ uint32_t *avdecl_map = state->cur->avdecl_map;
+
+ scope = (scope_datum_t *) datum;
+
+ /* check if the base already has a scope entry */
+ base_scope = hashtab_search(state->base->scope[symbol_num].table, id);
+ if (base_scope == NULL) {
+ scope_datum_t *new_scope;
+ if ((new_id = strdup(id)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((new_scope =
+ (scope_datum_t *) calloc(1, sizeof(*new_scope))) == NULL) {
+ free(new_id);
+ goto cleanup;
+ }
+ ret = hashtab_insert(state->base->scope[symbol_num].table,
+ (hashtab_key_t) new_id,
+ (hashtab_datum_t) new_scope);
+ if (ret) {
+ free(new_id);
+ free(new_scope);
+ goto cleanup;
+ }
+ new_scope->scope = SCOPE_REQ; /* this is reset further down */
+ base_scope = new_scope;
+ }
+ if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_DECL) {
+ /* this module declared symbol, so overwrite the old
+ * list with the new decl ids */
+ base_scope->scope = SCOPE_DECL;
+ free(base_scope->decl_ids);
+ base_scope->decl_ids = NULL;
+ base_scope->decl_ids_len = 0;
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ } else if (base_scope->scope == SCOPE_DECL && scope->scope == SCOPE_REQ) {
+ /* this module depended on a symbol that now exists,
+ * so don't do anything */
+ } else if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_REQ) {
+ /* symbol is still required, so add to the list */
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ } else {
+ /* this module declared a symbol, and it was already
+ * declared. only roles and users may be multiply
+ * declared; for all others this is an error. */
+ if (symbol_num != SYM_ROLES && symbol_num != SYM_USERS) {
+ ERR(state->handle,
+ "%s: Duplicate declaration in module: %s %s",
+ state->cur_mod_name,
+ symtab_names[state->symbol_num], id);
+ return -1;
+ }
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (add_i_to_a(avdecl_map[scope->decl_ids[i]],
+ &base_scope->decl_ids_len,
+ &base_scope->decl_ids) == -1) {
+ goto cleanup;
+ }
+ }
+ }
+ return 0;
+
+ cleanup:
+ ERR(state->handle, "Out of memory!");
+ return -1;
+}
+
+/* Copy a module over to a base, remapping all values within. After
+ * all identifiers and rules are done, copy the scoping information.
+ * This is when it checks for duplicate declarations. */
+static int copy_module(link_state_t * state, policy_module_t * module)
+{
+ int i, ret;
+ avrule_block_t *cur;
+ state->cur = module;
+ state->cur_mod_name = module->policy->name;
+
+ /* first copy all of the identifiers */
+ ret = copy_identifiers(state, module->policy->symtab, NULL);
+ if (ret) {
+ return ret;
+ }
+
+ /* next copy all of the avrule blocks */
+ for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+ ret = copy_avrule_block(state, module, cur);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ /* then copy the scoping tables */
+ for (i = 0; i < SYM_NUM; i++) {
+ state->symbol_num = i;
+ if (hashtab_map
+ (module->policy->scope[i].table, scope_copy_callback,
+ state)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/***** functions that check requirements and enable blocks in a module ******/
+
+/* borrowed from checkpolicy.c */
+
+struct find_perm_arg {
+ unsigned int valuep;
+ hashtab_key_t key;
+};
+
+static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *varg)
+{
+
+ struct find_perm_arg *arg = varg;
+
+ perm_datum_t *perdatum = (perm_datum_t *) datum;
+ if (arg->valuep == perdatum->s.value) {
+ arg->key = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check if the requirements are met for a single declaration. If all
+ * are met return 1. For the first requirement found to be missing,
+ * if 'missing_sym_num' and 'missing_value' are both not NULL then
+ * write to them the symbol number and value for the missing
+ * declaration. Then return 0 to indicate a missing declaration.
+ * Note that if a declaration had no requirement at all (e.g., an ELSE
+ * block) this returns 1. */
+static int is_decl_requires_met(link_state_t * state,
+ avrule_decl_t * decl,
+ struct missing_requirement *req)
+{
+ /* (This algorithm is very unoptimized. It performs many
+ * redundant checks. A very obvious improvement is to cache
+ * which symbols have been verified, so that they do not need
+ * to be re-checked.) */
+ unsigned int i, j;
+ ebitmap_t *bitmap;
+ char *id, *perm_id;
+ policydb_t *pol = state->base;
+ ebitmap_node_t *node;
+
+ /* check that all symbols have been satisfied */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (i == SYM_CLASSES) {
+ /* classes will be checked during permissions
+ * checking phase below */
+ continue;
+ }
+ bitmap = &decl->required.scope[i];
+ ebitmap_for_each_bit(bitmap, node, j) {
+ if (!ebitmap_node_get_bit(node, j)) {
+ continue;
+ }
+
+ /* check base's scope table */
+ id = pol->sym_val_to_name[i][j];
+ if (!is_id_enabled(id, state->base, i)) {
+ /* this symbol was not found */
+ if (req != NULL) {
+ req->symbol_type = i;
+ req->symbol_value = j + 1;
+ }
+ return 0;
+ }
+ }
+ }
+ /* check that all classes and permissions have been satisfied */
+ for (i = 0; i < decl->required.class_perms_len; i++) {
+
+ bitmap = decl->required.class_perms_map + i;
+ ebitmap_for_each_bit(bitmap, node, j) {
+ struct find_perm_arg fparg;
+ class_datum_t *cladatum;
+ uint32_t perm_value = j + 1;
+ int rc;
+ scope_datum_t *scope;
+
+ if (!ebitmap_node_get_bit(node, j)) {
+ continue;
+ }
+ id = pol->p_class_val_to_name[i];
+ cladatum = pol->class_val_to_struct[i];
+
+ scope =
+ hashtab_search(state->base->p_classes_scope.table,
+ id);
+ if (scope == NULL) {
+ ERR(state->handle,
+ "Could not find scope information for class %s",
+ id);
+ return -1;
+ }
+
+ fparg.valuep = perm_value;
+ fparg.key = NULL;
+
+ (void)hashtab_map(cladatum->permissions.table, find_perm,
+ &fparg);
+ if (fparg.key == NULL && cladatum->comdatum != NULL) {
+ rc = hashtab_map(cladatum->comdatum->permissions.table,
+ find_perm, &fparg);
+ assert(rc == 1);
+ }
+ perm_id = fparg.key;
+
+ assert(perm_id != NULL);
+ if (!is_perm_enabled(id, perm_id, state->base)) {
+ if (req != NULL) {
+ req->symbol_type = SYM_CLASSES;
+ req->symbol_value = i + 1;
+ req->perm_value = perm_value;
+ }
+ return 0;
+ }
+ }
+ }
+
+ /* all requirements have been met */
+ return 1;
+}
+
+static int debug_requirements(link_state_t * state, policydb_t * p)
+{
+ int ret;
+ avrule_block_t *cur;
+ missing_requirement_t req;
+ memset(&req, 0, sizeof(req));
+
+ for (cur = p->global; cur != NULL; cur = cur->next) {
+ if (cur->enabled != NULL)
+ continue;
+
+ ret = is_decl_requires_met(state, cur->branch_list, &req);
+ if (ret < 0) {
+ return ret;
+ } else if (ret == 0) {
+ const char *mod_name = cur->branch_list->module_name ?
+ cur->branch_list->module_name : "BASE";
+ if (req.symbol_type == SYM_CLASSES) {
+ struct find_perm_arg fparg;
+
+ class_datum_t *cladatum;
+ cladatum = p->class_val_to_struct[req.symbol_value - 1];
+
+ fparg.valuep = req.perm_value;
+ fparg.key = NULL;
+ (void)hashtab_map(cladatum->permissions.table,
+ find_perm, &fparg);
+
+ if (cur->flags & AVRULE_OPTIONAL) {
+ ERR(state->handle,
+ "%s[%d]'s optional requirements were not met: class %s, permission %s",
+ mod_name, cur->branch_list->decl_id,
+ p->p_class_val_to_name[req.symbol_value - 1],
+ fparg.key);
+ } else {
+ ERR(state->handle,
+ "%s[%d]'s global requirements were not met: class %s, permission %s",
+ mod_name, cur->branch_list->decl_id,
+ p->p_class_val_to_name[req.symbol_value - 1],
+ fparg.key);
+ }
+ } else {
+ if (cur->flags & AVRULE_OPTIONAL) {
+ ERR(state->handle,
+ "%s[%d]'s optional requirements were not met: %s %s",
+ mod_name, cur->branch_list->decl_id,
+ symtab_names[req.symbol_type],
+ p->sym_val_to_name[req.
+ symbol_type][req.
+ symbol_value
+ -
+ 1]);
+ } else {
+ ERR(state->handle,
+ "%s[%d]'s global requirements were not met: %s %s",
+ mod_name, cur->branch_list->decl_id,
+ symtab_names[req.symbol_type],
+ p->sym_val_to_name[req.
+ symbol_type][req.
+ symbol_value
+ -
+ 1]);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void print_missing_requirements(link_state_t * state,
+ avrule_block_t * cur,
+ missing_requirement_t * req)
+{
+ policydb_t *p = state->base;
+ const char *mod_name = cur->branch_list->module_name ?
+ cur->branch_list->module_name : "BASE";
+
+ if (req->symbol_type == SYM_CLASSES) {
+
+ struct find_perm_arg fparg;
+
+ class_datum_t *cladatum;
+ cladatum = p->class_val_to_struct[req->symbol_value - 1];
+
+ fparg.valuep = req->perm_value;
+ fparg.key = NULL;
+ (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg);
+
+ ERR(state->handle,
+ "%s's global requirements were not met: class %s, permission %s",
+ mod_name,
+ p->p_class_val_to_name[req->symbol_value - 1], fparg.key);
+ } else {
+ ERR(state->handle,
+ "%s's global requirements were not met: %s %s",
+ mod_name,
+ symtab_names[req->symbol_type],
+ p->sym_val_to_name[req->symbol_type][req->symbol_value - 1]);
+ }
+}
+
+/* Enable all of the avrule_decl blocks for the policy. This simple
+ * algorithm is the following:
+ *
+ * 1) Enable all of the non-else avrule_decls for all blocks.
+ * 2) Iterate through the non-else decls looking for decls whose requirements
+ * are not met.
+ * 2a) If the decl is non-optional, return immediately with an error.
+ * 2b) If the decl is optional, disable the block and mark changed = 1
+ * 3) If changed == 1 goto 2.
+ * 4) Iterate through all blocks looking for those that have no enabled
+ * decl. If the block has an else decl, enable.
+ *
+ * This will correctly handle all dependencies, including mutual and
+ * cicular. The only downside is that it is slow.
+ */
+static int enable_avrules(link_state_t * state, policydb_t * pol)
+{
+ int changed = 1;
+ avrule_block_t *block;
+ avrule_decl_t *decl;
+ missing_requirement_t req;
+ int ret = 0, rc;
+
+ if (state->verbose) {
+ INFO(state->handle, "Determining which avrules to enable.");
+ }
+
+ /* 1) enable all of the non-else blocks */
+ for (block = pol->global; block != NULL; block = block->next) {
+ block->enabled = block->branch_list;
+ block->enabled->enabled = 1;
+ for (decl = block->branch_list->next; decl != NULL;
+ decl = decl->next)
+ decl->enabled = 0;
+ }
+
+ /* 2) Iterate */
+ while (changed) {
+ changed = 0;
+ for (block = pol->global; block != NULL; block = block->next) {
+ if (block->enabled == NULL) {
+ continue;
+ }
+ decl = block->branch_list;
+ if (state->verbose) {
+ const char *mod_name = decl->module_name ?
+ decl->module_name : "BASE";
+ INFO(state->handle, "check module %s decl %d\n",
+ mod_name, decl->decl_id);
+ }
+ rc = is_decl_requires_met(state, decl, &req);
+ if (rc < 0) {
+ ret = SEPOL_ERR;
+ goto out;
+ } else if (rc == 0) {
+ decl->enabled = 0;
+ block->enabled = NULL;
+ changed = 1;
+ if (!(block->flags & AVRULE_OPTIONAL)) {
+ print_missing_requirements(state, block,
+ &req);
+ ret = SEPOL_EREQ;
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* 4) else handling
+ *
+ * Iterate through all of the blocks skipping the first (which is the
+ * global block, is required to be present, and cannot have an else).
+ * If the block is disabled and has an else decl, enable that.
+ *
+ * This code assumes that the second block in the branch list is the else
+ * block. This is currently supported by the compiler.
+ */
+ for (block = pol->global->next; block != NULL; block = block->next) {
+ if (block->enabled == NULL) {
+ if (block->branch_list->next != NULL) {
+ block->enabled = block->branch_list->next;
+ block->branch_list->next->enabled = 1;
+ }
+ }
+ }
+
+ out:
+ if (state->verbose)
+ debug_requirements(state, pol);
+
+ return ret;
+}
+
+/*********** the main linking functions ***********/
+
+/* Given a module's policy, normalize all conditional expressions
+ * within. Return 0 on success, -1 on error. */
+static int cond_normalize(policydb_t * p)
+{
+ avrule_block_t *block;
+ for (block = p->global; block != NULL; block = block->next) {
+ avrule_decl_t *decl;
+ for (decl = block->branch_list; decl != NULL; decl = decl->next) {
+ cond_list_t *cond = decl->cond_list;
+ while (cond) {
+ if (cond_normalize_expr(p, cond) < 0)
+ return -1;
+ cond = cond->next;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Allocate space for the various remapping arrays. */
+static int prepare_module(link_state_t * state, policy_module_t * module)
+{
+ int i;
+ uint32_t items, num_decls = 0;
+ avrule_block_t *cur;
+
+ /* allocate the maps */
+ for (i = 0; i < SYM_NUM; i++) {
+ items = module->policy->symtab[i].nprim;
+ if ((module->map[i] =
+ (uint32_t *) calloc(items,
+ sizeof(*module->map[i]))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ }
+
+ /* allocate the permissions remap here */
+ items = module->policy->p_classes.nprim;
+ if ((module->perm_map_len =
+ calloc(items, sizeof(*module->perm_map_len))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ if ((module->perm_map =
+ calloc(items, sizeof(*module->perm_map))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* allocate a map for avrule_decls */
+ for (cur = module->policy->global; cur != NULL; cur = cur->next) {
+ avrule_decl_t *decl;
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (decl->decl_id > num_decls) {
+ num_decls = decl->decl_id;
+ }
+ }
+ }
+ num_decls++;
+ if ((module->avdecl_map = calloc(num_decls, sizeof(uint32_t))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ module->num_decls = num_decls;
+
+ /* normalize conditionals within */
+ if (cond_normalize(module->policy) < 0) {
+ ERR(state->handle,
+ "Error while normalizing conditionals within the module %s.",
+ module->policy->name);
+ return -1;
+ }
+ return 0;
+}
+
+static int prepare_base(link_state_t * state, uint32_t num_mod_decls)
+{
+ avrule_block_t *cur = state->base->global;
+ assert(cur != NULL);
+ state->next_decl_id = 0;
+
+ /* iterate through all of the declarations in the base, to
+ determine what the next decl_id should be */
+ while (cur != NULL) {
+ avrule_decl_t *decl;
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (decl->decl_id > state->next_decl_id) {
+ state->next_decl_id = decl->decl_id;
+ }
+ }
+ state->last_avrule_block = cur;
+ cur = cur->next;
+ }
+ state->last_base_avrule_block = state->last_avrule_block;
+ state->next_decl_id++;
+
+ /* allocate the table mapping from base's decl_id to its
+ * avrule_decls and set the initial mappings */
+ free(state->base->decl_val_to_struct);
+ if ((state->base->decl_val_to_struct =
+ calloc(state->next_decl_id + num_mod_decls,
+ sizeof(*(state->base->decl_val_to_struct)))) == NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ /* This allocates the decl block to module mapping used for error reporting */
+ if ((state->decl_to_mod = calloc(state->next_decl_id + num_mod_decls,
+ sizeof(*(state->decl_to_mod)))) ==
+ NULL) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+ cur = state->base->global;
+ while (cur != NULL) {
+ avrule_decl_t *decl = cur->branch_list;
+ while (decl != NULL) {
+ state->base->decl_val_to_struct[decl->decl_id - 1] =
+ decl;
+ state->decl_to_mod[decl->decl_id] = state->base;
+ decl = decl->next;
+ }
+ cur = cur->next;
+ }
+
+ /* normalize conditionals within */
+ if (cond_normalize(state->base) < 0) {
+ ERR(state->handle,
+ "Error while normalizing conditionals within the base module.");
+ return -1;
+ }
+ return 0;
+}
+
+static int expand_role_attributes(hashtab_key_t key, hashtab_datum_t datum,
+ void * data)
+{
+ char *id;
+ role_datum_t *role, *sub_attr;
+ link_state_t *state;
+ unsigned int i;
+ ebitmap_node_t *rnode;
+
+ id = key;
+ role = (role_datum_t *)datum;
+ state = (link_state_t *)data;
+
+ if (strcmp(id, OBJECT_R) == 0){
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ if (state->verbose)
+ INFO(state->handle, "expanding role attribute %s", id);
+
+restart:
+ ebitmap_for_each_bit(&role->roles, rnode, i) {
+ if (ebitmap_node_get_bit(rnode, i)) {
+ sub_attr = state->base->role_val_to_struct[i];
+ if (sub_attr->flavor != ROLE_ATTRIB)
+ continue;
+
+ /* remove the sub role attribute from the parent
+ * role attribute's roles ebitmap */
+ if (ebitmap_set_bit(&role->roles, i, 0))
+ return -1;
+
+ /* loop dependency of role attributes */
+ if (sub_attr->s.value == role->s.value)
+ continue;
+
+ /* now go on to expand a sub role attribute
+ * by escalating its roles ebitmap */
+ if (ebitmap_union(&role->roles, &sub_attr->roles)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ /* sub_attr->roles may contain other role attributes,
+ * re-scan the parent role attribute's roles ebitmap */
+ goto restart;
+ }
+ }
+
+ return 0;
+}
+
+/* For any role attribute in a declaration's local symtab[SYM_ROLES] table,
+ * copy its roles ebitmap into its duplicate's in the base->p_roles.table.
+ */
+static int populate_decl_roleattributes(hashtab_key_t key,
+ hashtab_datum_t datum,
+ void *data)
+{
+ char *id = key;
+ role_datum_t *decl_role, *base_role;
+ link_state_t *state = (link_state_t *)data;
+
+ decl_role = (role_datum_t *)datum;
+
+ if (strcmp(id, OBJECT_R) == 0) {
+ /* object_r is never a role attribute by far */
+ return 0;
+ }
+
+ if (decl_role->flavor != ROLE_ATTRIB)
+ return 0;
+
+ base_role = (role_datum_t *)hashtab_search(state->base->p_roles.table,
+ id);
+ assert(base_role != NULL && base_role->flavor == ROLE_ATTRIB);
+
+ if (ebitmap_union(&base_role->roles, &decl_role->roles)) {
+ ERR(state->handle, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int populate_roleattributes(link_state_t *state, policydb_t *pol)
+{
+ avrule_block_t *block;
+ avrule_decl_t *decl;
+
+ if (state->verbose)
+ INFO(state->handle, "Populating role-attribute relationship "
+ "from enabled declarations' local symtab.");
+
+ /* Iterate through all of the blocks skipping the first(which is the
+ * global block, is required to be present and can't have an else).
+ * If the block is disabled or not having an enabled decl, skip it.
+ */
+ for (block = pol->global->next; block != NULL; block = block->next)
+ {
+ decl = block->enabled;
+ if (decl == NULL || decl->enabled == 0)
+ continue;
+
+ if (hashtab_map(decl->symtab[SYM_ROLES].table,
+ populate_decl_roleattributes, state))
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Link a set of modules into a base module. This process is somewhat
+ * similar to an actual compiler: it requires a set of order dependent
+ * steps. The base and every module must have been indexed prior to
+ * calling this function.
+ */
+int link_modules(sepol_handle_t * handle,
+ policydb_t * b, policydb_t ** mods, int len, int verbose)
+{
+ int i, ret, retval = -1;
+ policy_module_t **modules = NULL;
+ link_state_t state;
+ uint32_t num_mod_decls = 0;
+
+ memset(&state, 0, sizeof(state));
+ state.base = b;
+ state.verbose = verbose;
+ state.handle = handle;
+
+ if (b->policy_type != POLICY_BASE) {
+ ERR(state.handle, "Target of link was not a base policy.");
+ return -1;
+ }
+
+ /* first allocate some space to hold the maps from module
+ * symbol's value to the destination symbol value; then do
+ * other preparation work */
+ if ((modules =
+ (policy_module_t **) calloc(len, sizeof(*modules))) == NULL) {
+ ERR(state.handle, "Out of memory!");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ if (mods[i]->policy_type != POLICY_MOD) {
+ ERR(state.handle,
+ "Tried to link in a policy that was not a module.");
+ goto cleanup;
+ }
+
+ if (mods[i]->mls != b->mls) {
+ if (b->mls)
+ ERR(state.handle,
+ "Tried to link in a non-MLS module with an MLS base.");
+ else
+ ERR(state.handle,
+ "Tried to link in an MLS module with a non-MLS base.");
+ goto cleanup;
+ }
+
+ if ((modules[i] =
+ (policy_module_t *) calloc(1,
+ sizeof(policy_module_t))) ==
+ NULL) {
+ ERR(state.handle, "Out of memory!");
+ goto cleanup;
+ }
+ modules[i]->policy = mods[i];
+ if (prepare_module(&state, modules[i]) == -1) {
+ goto cleanup;
+ }
+ num_mod_decls += modules[i]->num_decls;
+ }
+ if (prepare_base(&state, num_mod_decls) == -1) {
+ goto cleanup;
+ }
+
+ /* copy all types, declared and required */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ state.cur_mod_name = modules[i]->policy->name;
+ ret =
+ hashtab_map(modules[i]->policy->p_types.table,
+ type_copy_callback, &state);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ /* then copy everything else, including aliases, and fixup attributes */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ state.cur_mod_name = modules[i]->policy->name;
+ ret =
+ copy_identifiers(&state, modules[i]->policy->symtab, NULL);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ if (policydb_index_others(state.handle, state.base, 0)) {
+ ERR(state.handle, "Error while indexing others");
+ goto cleanup;
+ }
+
+ /* copy and remap the module's data over to base */
+ for (i = 0; i < len; i++) {
+ state.cur = modules[i];
+ ret = copy_module(&state, modules[i]);
+ if (ret) {
+ retval = ret;
+ goto cleanup;
+ }
+ }
+
+ /* re-index base, for symbols were added to symbol tables */
+ if (policydb_index_classes(state.base)) {
+ ERR(state.handle, "Error while indexing classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(state.handle, state.base, 0)) {
+ ERR(state.handle, "Error while indexing others");
+ goto cleanup;
+ }
+
+ if (enable_avrules(&state, state.base)) {
+ retval = SEPOL_EREQ;
+ goto cleanup;
+ }
+
+ /* Now that all role attribute's roles ebitmap have been settled,
+ * escalate sub role attribute's roles ebitmap into that of parent.
+ *
+ * First, since some role-attribute relationships could be recorded
+ * in some decl's local symtab(see get_local_role()), we need to
+ * populate them up to the base.p_roles table. */
+ if (populate_roleattributes(&state, state.base)) {
+ retval = SEPOL_EREQ;
+ goto cleanup;
+ }
+
+ /* Now do the escalation. */
+ if (hashtab_map(state.base->p_roles.table, expand_role_attributes,
+ &state))
+ goto cleanup;
+
+ retval = 0;
+ cleanup:
+ for (i = 0; modules != NULL && i < len; i++) {
+ policy_module_destroy(modules[i]);
+ }
+ free(modules);
+ free(state.decl_to_mod);
+ return retval;
+}
diff --git a/libsepol/src/mls.c b/libsepol/src/mls.c
new file mode 100644
index 0000000..1e84bb7
--- /dev/null
+++ b/libsepol/src/mls.c
@@ -0,0 +1,798 @@
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the multi-level security (MLS) policy.
+ */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/context.h>
+
+#include <stdlib.h>
+
+#include "handle.h"
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+int mls_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * mls, char **str)
+{
+
+ char *ptr = NULL, *ptr2 = NULL;
+
+ /* Temporary buffer - length + NULL terminator */
+ int len = mls_compute_context_len(policydb, mls) + 1;
+
+ ptr = (char *)malloc(len);
+ if (ptr == NULL)
+ goto omem;
+
+ /* Final string w/ ':' cut off */
+ ptr2 = (char *)malloc(len - 1);
+ if (ptr2 == NULL)
+ goto omem;
+
+ mls_sid_to_context(policydb, mls, &ptr);
+ ptr -= len - 1;
+ strcpy(ptr2, ptr + 1);
+
+ free(ptr);
+ *str = ptr2;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not convert mls context to string");
+
+ free(ptr);
+ free(ptr2);
+ return STATUS_ERR;
+
+}
+
+int mls_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const char *str, context_struct_t * mls)
+{
+
+ char *tmp = strdup(str);
+ char *tmp_cp = tmp;
+ if (!tmp)
+ goto omem;
+
+ if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
+ ERR(handle, "invalid MLS context %s", str);
+ free(tmp);
+ goto err;
+ }
+
+ free(tmp);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not construct mls context structure");
+ return STATUS_ERR;
+}
+
+/*
+ * Return the length in bytes for the MLS fields of the
+ * security context string representation of `context'.
+ */
+int mls_compute_context_len(const policydb_t * policydb,
+ const context_struct_t * context)
+{
+
+ unsigned int i, l, len, range;
+ ebitmap_node_t *cnode;
+
+ if (!policydb->mls)
+ return 0;
+
+ len = 1; /* for the beginning ":" */
+ for (l = 0; l < 2; l++) {
+ range = 0;
+ len +=
+ strlen(policydb->
+ p_sens_val_to_name[context->range.level[l].sens -
+ 1]);
+
+ ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (range) {
+ range++;
+ continue;
+ }
+
+ len +=
+ strlen(policydb->p_cat_val_to_name[i]) + 1;
+ range++;
+ } else {
+ if (range > 1)
+ len +=
+ strlen(policydb->
+ p_cat_val_to_name[i - 1]) +
+ 1;
+ range = 0;
+ }
+ }
+ /* Handle case where last category is the end of range */
+ if (range > 1)
+ len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
+
+ if (l == 0) {
+ if (mls_level_eq(&context->range.level[0],
+ &context->range.level[1]))
+ break;
+ else
+ len++;
+ }
+ }
+
+ return len;
+}
+
+/*
+ * Write the security context string representation of
+ * the MLS fields of `context' into the string `*scontext'.
+ * Update `*scontext' to point to the end of the MLS fields.
+ */
+void mls_sid_to_context(const policydb_t * policydb,
+ const context_struct_t * context, char **scontext)
+{
+
+ char *scontextp;
+ unsigned int i, l, range, wrote_sep;
+ ebitmap_node_t *cnode;
+
+ if (!policydb->mls)
+ return;
+
+ scontextp = *scontext;
+
+ *scontextp = ':';
+ scontextp++;
+
+ for (l = 0; l < 2; l++) {
+ range = 0;
+ wrote_sep = 0;
+ strcpy(scontextp,
+ policydb->p_sens_val_to_name[context->range.level[l].
+ sens - 1]);
+ scontextp +=
+ strlen(policydb->
+ p_sens_val_to_name[context->range.level[l].sens -
+ 1]);
+ /* categories */
+ ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (range) {
+ range++;
+ continue;
+ }
+
+ if (!wrote_sep) {
+ *scontextp++ = ':';
+ wrote_sep = 1;
+ } else
+ *scontextp++ = ',';
+ strcpy(scontextp,
+ policydb->p_cat_val_to_name[i]);
+ scontextp +=
+ strlen(policydb->p_cat_val_to_name[i]);
+ range++;
+ } else {
+ if (range > 1) {
+ if (range > 2)
+ *scontextp++ = '.';
+ else
+ *scontextp++ = ',';
+
+ strcpy(scontextp,
+ policydb->p_cat_val_to_name[i -
+ 1]);
+ scontextp +=
+ strlen(policydb->
+ p_cat_val_to_name[i - 1]);
+ }
+ range = 0;
+ }
+ }
+ /* Handle case where last category is the end of range */
+ if (range > 1) {
+ if (range > 2)
+ *scontextp++ = '.';
+ else
+ *scontextp++ = ',';
+
+ strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
+ scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
+ }
+
+ if (l == 0) {
+ if (mls_level_eq(&context->range.level[0],
+ &context->range.level[1]))
+ break;
+ else {
+ *scontextp = '-';
+ scontextp++;
+ }
+ }
+ }
+
+ *scontext = scontextp;
+ return;
+}
+
+/*
+ * Return 1 if the MLS fields in the security context
+ * structure `c' are valid. Return 0 otherwise.
+ */
+int mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
+{
+
+ level_datum_t *levdatum;
+ user_datum_t *usrdatum;
+ unsigned int i, l;
+ ebitmap_node_t *cnode;
+
+ if (!p->mls)
+ return 1;
+
+ /*
+ * MLS range validity checks: high must dominate low, low level must
+ * be valid (category set <-> sensitivity check), and high level must
+ * be valid (category set <-> sensitivity check)
+ */
+ if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
+ /* High does not dominate low. */
+ return 0;
+
+ for (l = 0; l < 2; l++) {
+ if (!c->range.level[l].sens
+ || c->range.level[l].sens > p->p_levels.nprim)
+ return 0;
+ levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
+ p->
+ p_sens_val_to_name
+ [c->range.level[l].
+ sens - 1]);
+ if (!levdatum)
+ return 0;
+
+ ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
+ /*
+ * Category may not be associated with
+ * sensitivity in low level.
+ */
+ return 0;
+ }
+ }
+ }
+
+ if (c->role == OBJECT_R_VAL)
+ return 1;
+
+ /*
+ * User must be authorized for the MLS range.
+ */
+ if (!c->user || c->user > p->p_users.nprim)
+ return 0;
+ usrdatum = p->user_val_to_struct[c->user - 1];
+ if (!mls_range_contains(usrdatum->exp_range, c->range))
+ return 0; /* user may not be associated with range */
+
+ return 1;
+}
+
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'. Update `*scontext' to
+ * point to the end of the string representation of
+ * the MLS fields.
+ *
+ * This function modifies the string in place, inserting
+ * NULL characters to terminate the MLS fields.
+ */
+int mls_context_to_sid(const policydb_t * policydb,
+ char oldc, char **scontext, context_struct_t * context)
+{
+
+ char delim;
+ char *scontextp, *p, *rngptr;
+ level_datum_t *levdatum;
+ cat_datum_t *catdatum, *rngdatum;
+ unsigned int l;
+
+ if (!policydb->mls)
+ return 0;
+
+ /* No MLS component to the security context */
+ if (!oldc)
+ goto err;
+
+ /* Extract low sensitivity. */
+ scontextp = p = *scontext;
+ while (*p && *p != ':' && *p != '-')
+ p++;
+
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+
+ for (l = 0; l < 2; l++) {
+ levdatum =
+ (level_datum_t *) hashtab_search(policydb->p_levels.table,
+ (hashtab_key_t) scontextp);
+
+ if (!levdatum)
+ goto err;
+
+ context->range.level[l].sens = levdatum->level->sens;
+
+ if (delim == ':') {
+ /* Extract category set. */
+ while (1) {
+ scontextp = p;
+ while (*p && *p != ',' && *p != '-')
+ p++;
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+
+ /* Separate into range if exists */
+ if ((rngptr = strchr(scontextp, '.')) != NULL) {
+ /* Remove '.' */
+ *rngptr++ = 0;
+ }
+
+ catdatum =
+ (cat_datum_t *) hashtab_search(policydb->
+ p_cats.table,
+ (hashtab_key_t)
+ scontextp);
+ if (!catdatum)
+ goto err;
+
+ if (ebitmap_set_bit
+ (&context->range.level[l].cat,
+ catdatum->s.value - 1, 1))
+ goto err;
+
+ /* If range, set all categories in range */
+ if (rngptr) {
+ unsigned int i;
+
+ rngdatum = (cat_datum_t *)
+ hashtab_search(policydb->p_cats.
+ table,
+ (hashtab_key_t)
+ rngptr);
+ if (!rngdatum)
+ goto err;
+
+ if (catdatum->s.value >=
+ rngdatum->s.value)
+ goto err;
+
+ for (i = catdatum->s.value;
+ i < rngdatum->s.value; i++) {
+ if (ebitmap_set_bit
+ (&context->range.level[l].
+ cat, i, 1))
+ goto err;
+ }
+ }
+
+ if (delim != ',')
+ break;
+ }
+ }
+ if (delim == '-') {
+ /* Extract high sensitivity. */
+ scontextp = p;
+ while (*p && *p != ':')
+ p++;
+
+ delim = *p;
+ if (delim != 0)
+ *p++ = 0;
+ } else
+ break;
+ }
+
+ /* High level is missing, copy low level */
+ if (l == 0) {
+ if (mls_level_cpy(&context->range.level[1],
+ &context->range.level[0]) < 0)
+ goto err;
+ }
+ *scontext = ++p;
+
+ return STATUS_SUCCESS;
+
+ err:
+ return STATUS_ERR;
+}
+
+/*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(context_struct_t * dst,
+ context_struct_t * src)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range from the source context */
+ for (l = 0; l < 2; l++) {
+ dst->range.level[l].sens = src->range.level[l].sens;
+ rc = ebitmap_cpy(&dst->range.level[l].cat,
+ &src->range.level[l].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(context_struct_t * dst,
+ context_struct_t * src)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range from the source context */
+ for (l = 0; l < 2; l++) {
+ dst->range.level[l].sens = src->range.level[0].sens;
+ rc = ebitmap_cpy(&dst->range.level[l].cat,
+ &src->range.level[0].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(context_struct_t * context, mls_range_t * range)
+{
+ int l, rc = 0;
+
+ /* Copy the MLS range into the context */
+ for (l = 0; l < 2; l++) {
+ context->range.level[l].sens = range->level[l].sens;
+ rc = ebitmap_cpy(&context->range.level[l].cat,
+ &range->level[l].cat);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+ context_struct_t * usercon, int mls)
+{
+ if (mls) {
+ mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
+ mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
+ mls_level_t *user_low = &(user->exp_range.level[0]);
+ mls_level_t *user_clr = &(user->exp_range.level[1]);
+ mls_level_t *user_def = &(user->exp_dfltlevel);
+ mls_level_t *usercon_sen = &(usercon->range.level[0]);
+ mls_level_t *usercon_clr = &(usercon->range.level[1]);
+
+ /* Honor the user's default level if we can */
+ if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+ *usercon_sen = *user_def;
+ } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+ *usercon_sen = *fromcon_sen;
+ } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+ *usercon_sen = *user_low;
+ } else
+ return -EINVAL;
+
+ /* Lower the clearance of available contexts
+ if the clearance of "fromcon" is lower than
+ that of the user's default clearance (but
+ only if the "fromcon" clearance dominates
+ the user's computed sensitivity level) */
+ if (mls_level_dom(user_clr, fromcon_clr)) {
+ *usercon_clr = *fromcon_clr;
+ } else if (mls_level_dom(fromcon_clr, user_clr)) {
+ *usercon_clr = *user_clr;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert the MLS fields in the security context
+ * structure `c' from the values specified in the
+ * policy `oldp' to the values specified in the policy `newp'.
+ */
+int mls_convert_context(policydb_t * oldp,
+ policydb_t * newp, context_struct_t * c)
+{
+ level_datum_t *levdatum;
+ cat_datum_t *catdatum;
+ ebitmap_t bitmap;
+ unsigned int l, i;
+ ebitmap_node_t *cnode;
+
+ if (!oldp->mls)
+ return 0;
+
+ for (l = 0; l < 2; l++) {
+ levdatum =
+ (level_datum_t *) hashtab_search(newp->p_levels.table,
+ oldp->
+ p_sens_val_to_name[c->
+ range.
+ level
+ [l].
+ sens -
+ 1]);
+
+ if (!levdatum)
+ return -EINVAL;
+ c->range.level[l].sens = levdatum->level->sens;
+
+ ebitmap_init(&bitmap);
+ ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ int rc;
+
+ catdatum =
+ (cat_datum_t *) hashtab_search(newp->p_cats.
+ table,
+ oldp->
+ p_cat_val_to_name
+ [i]);
+ if (!catdatum)
+ return -EINVAL;
+ rc = ebitmap_set_bit(&bitmap,
+ catdatum->s.value - 1, 1);
+ if (rc)
+ return rc;
+ }
+ }
+ ebitmap_destroy(&c->range.level[l].cat);
+ c->range.level[l].cat = bitmap;
+ }
+
+ return 0;
+}
+
+int mls_compute_sid(policydb_t * policydb,
+ context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ uint32_t specified, context_struct_t * newcontext)
+{
+ range_trans_t *rtr;
+ if (!policydb->mls)
+ return 0;
+
+ switch (specified) {
+ case AVTAB_TRANSITION:
+ /* Look for a range transition rule. */
+ for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
+ if (rtr->source_type == scontext->type &&
+ rtr->target_type == tcontext->type &&
+ rtr->target_class == tclass) {
+ /* Set the range from the rule */
+ return mls_range_set(newcontext,
+ &rtr->target_range);
+ }
+ }
+ /* Fallthrough */
+ case AVTAB_CHANGE:
+ if (tclass == SECCLASS_PROCESS)
+ /* Use the process MLS attributes. */
+ return mls_copy_context(newcontext, scontext);
+ else
+ /* Use the process effective MLS attributes. */
+ return mls_scopy_context(newcontext, scontext);
+ case AVTAB_MEMBER:
+ /* Only polyinstantiate the MLS attributes if
+ the type is being polyinstantiated */
+ if (newcontext->type != tcontext->type) {
+ /* Use the process effective MLS attributes. */
+ return mls_scopy_context(newcontext, scontext);
+ } else {
+ /* Use the related object MLS attributes. */
+ return mls_copy_context(newcontext, tcontext);
+ }
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+int sepol_mls_contains(sepol_handle_t * handle,
+ sepol_policydb_t * policydb,
+ const char *mls1, const char *mls2, int *response)
+{
+
+ context_struct_t *ctx1 = NULL, *ctx2 = NULL;
+ ctx1 = malloc(sizeof(context_struct_t));
+ ctx2 = malloc(sizeof(context_struct_t));
+ if (ctx1 == NULL || ctx2 == NULL)
+ goto omem;
+ context_init(ctx1);
+ context_init(ctx2);
+
+ if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
+ goto err;
+
+ if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
+ goto err;
+
+ *response = mls_range_contains(ctx1->range, ctx2->range);
+ context_destroy(ctx1);
+ context_destroy(ctx2);
+ free(ctx1);
+ free(ctx2);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not check if mls context %s contains %s",
+ mls1, mls2);
+ context_destroy(ctx1);
+ context_destroy(ctx2);
+ free(ctx1);
+ free(ctx2);
+ return STATUS_ERR;
+}
+
+int sepol_mls_check(sepol_handle_t * handle,
+ sepol_policydb_t * policydb, const char *mls)
+{
+
+ int ret;
+ context_struct_t *con = malloc(sizeof(context_struct_t));
+ if (!con) {
+ ERR(handle, "out of memory, could not check if "
+ "mls context %s is valid", mls);
+ return STATUS_ERR;
+ }
+ context_init(con);
+
+ ret = mls_from_string(handle, &policydb->p, mls, con);
+ context_destroy(con);
+ free(con);
+ return ret;
+}
+
+void mls_semantic_cat_init(mls_semantic_cat_t * c)
+{
+ memset(c, 0, sizeof(mls_semantic_cat_t));
+}
+
+void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
+{
+ /* it's currently a simple struct - really nothing to destroy */
+ return;
+}
+
+void mls_semantic_level_init(mls_semantic_level_t * l)
+{
+ memset(l, 0, sizeof(mls_semantic_level_t));
+}
+
+void mls_semantic_level_destroy(mls_semantic_level_t * l)
+{
+ mls_semantic_cat_t *cur, *next;
+
+ if (l == NULL)
+ return;
+
+ next = l->cat;
+ while (next) {
+ cur = next;
+ next = cur->next;
+ mls_semantic_cat_destroy(cur);
+ free(cur);
+ }
+}
+
+int mls_semantic_level_cpy(mls_semantic_level_t * dst,
+ mls_semantic_level_t * src)
+{
+ mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL;
+
+ mls_semantic_level_init(dst);
+ dst->sens = src->sens;
+ cat = src->cat;
+ while (cat) {
+ newcat =
+ (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!newcat)
+ goto err;
+
+ mls_semantic_cat_init(newcat);
+ if (lnewcat)
+ lnewcat->next = newcat;
+ else
+ dst->cat = newcat;
+
+ newcat->low = cat->low;
+ newcat->high = cat->high;
+
+ lnewcat = newcat;
+ cat = cat->next;
+ }
+ return 0;
+
+ err:
+ mls_semantic_level_destroy(dst);
+ return -1;
+}
+
+void mls_semantic_range_init(mls_semantic_range_t * r)
+{
+ mls_semantic_level_init(&r->level[0]);
+ mls_semantic_level_init(&r->level[1]);
+}
+
+void mls_semantic_range_destroy(mls_semantic_range_t * r)
+{
+ mls_semantic_level_destroy(&r->level[0]);
+ mls_semantic_level_destroy(&r->level[1]);
+}
+
+int mls_semantic_range_cpy(mls_semantic_range_t * dst,
+ mls_semantic_range_t * src)
+{
+ if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
+ return -1;
+
+ if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
+ mls_semantic_level_destroy(&dst->level[0]);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/libsepol/src/mls.h b/libsepol/src/mls.h
new file mode 100644
index 0000000..98da3d3
--- /dev/null
+++ b/libsepol/src/mls.h
@@ -0,0 +1,67 @@
+/* Author: Stephen Smalley, <sds@epoch.ncsc.mil>
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEPOL_MLS_INTERNAL_H_
+#define _SEPOL_MLS_INTERNAL_H_
+
+#include "policydb_internal.h"
+#include <sepol/policydb/context.h>
+#include "handle.h"
+
+extern int mls_from_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const char *str, context_struct_t * mls);
+
+extern int mls_to_string(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ const context_struct_t * mls, char **str);
+
+/* Deprecated */
+extern int mls_compute_context_len(const policydb_t * policydb,
+ const context_struct_t * context);
+
+/* Deprecated */
+extern void mls_sid_to_context(const policydb_t * policydb,
+ const context_struct_t * context,
+ char **scontext);
+
+/* Deprecated */
+extern int mls_context_to_sid(const policydb_t * policydb,
+ char oldc,
+ char **scontext, context_struct_t * context);
+
+extern int mls_context_isvalid(const policydb_t * p,
+ const context_struct_t * c);
+
+extern int mls_convert_context(policydb_t * oldp,
+ policydb_t * newp, context_struct_t * context);
+
+extern int mls_compute_sid(policydb_t * policydb,
+ context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ uint32_t specified, context_struct_t * newcontext);
+
+extern int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
+ context_struct_t * usercon, int mls);
+
+#endif
diff --git a/libsepol/src/module.c b/libsepol/src/module.c
new file mode 100644
index 0000000..1665ede
--- /dev/null
+++ b/libsepol/src/module.c
@@ -0,0 +1,1008 @@
+/* Author: Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2004-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policydb_internal.h"
+#include "module_internal.h"
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/module.h>
+#include "debug.h"
+#include "private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
+#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
+#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
+#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
+
+static int policy_file_seek(struct policy_file *fp, size_t offset)
+{
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ if (offset > LONG_MAX) {
+ errno = EFAULT;
+ return -1;
+ }
+ return fseek(fp->fp, (long)offset, SEEK_SET);
+ case PF_USE_MEMORY:
+ if (offset > fp->size) {
+ errno = EFAULT;
+ return -1;
+ }
+ fp->data -= fp->size - fp->len;
+ fp->data += offset;
+ fp->len = fp->size - offset;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int policy_file_length(struct policy_file *fp, size_t *out)
+{
+ long prev_offset, end_offset;
+ int rc;
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ prev_offset = ftell(fp->fp);
+ if (prev_offset < 0)
+ return prev_offset;
+ rc = fseek(fp->fp, 0L, SEEK_END);
+ if (rc < 0)
+ return rc;
+ end_offset = ftell(fp->fp);
+ if (end_offset < 0)
+ return end_offset;
+ rc = fseek(fp->fp, prev_offset, SEEK_SET);
+ if (rc < 0)
+ return rc;
+ *out = end_offset;
+ break;
+ case PF_USE_MEMORY:
+ *out = fp->size;
+ break;;
+ default:
+ *out = 0;
+ break;
+ }
+ return 0;
+}
+
+static int module_package_init(sepol_module_package_t * p)
+{
+ memset(p, 0, sizeof(sepol_module_package_t));
+ if (sepol_policydb_create(&p->policy))
+ return -1;
+
+ p->version = 1;
+ return 0;
+}
+
+static int set_char(char **field, char *data, size_t len)
+{
+ if (*field) {
+ free(*field);
+ *field = NULL;
+ }
+ if (len) {
+ *field = malloc(len);
+ if (!*field)
+ return -1;
+ memcpy(*field, data, len);
+ }
+ return 0;
+}
+
+int sepol_module_package_create(sepol_module_package_t ** p)
+{
+ int rc;
+
+ *p = calloc(1, sizeof(sepol_module_package_t));
+ if (!(*p))
+ return -1;
+
+ rc = module_package_init(*p);
+ if (rc < 0)
+ free(*p);
+
+ return rc;
+}
+
+hidden_def(sepol_module_package_create)
+
+/* Deallocates all memory associated with a module package, including
+ * the pointer itself. Does nothing if p is NULL.
+ */
+void sepol_module_package_free(sepol_module_package_t * p)
+{
+ if (p == NULL)
+ return;
+
+ sepol_policydb_free(p->policy);
+ free(p->file_contexts);
+ free(p->seusers);
+ free(p->user_extra);
+ free(p->netfilter_contexts);
+ free(p);
+}
+
+hidden_def(sepol_module_package_free)
+
+char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
+{
+ return p->file_contexts;
+}
+
+size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
+{
+ return p->file_contexts_len;
+}
+
+char *sepol_module_package_get_seusers(sepol_module_package_t * p)
+{
+ return p->seusers;
+}
+
+size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
+{
+ return p->seusers_len;
+}
+
+char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
+{
+ return p->user_extra;
+}
+
+size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
+{
+ return p->user_extra_len;
+}
+
+char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
+{
+ return p->netfilter_contexts;
+}
+
+size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
+ p)
+{
+ return p->netfilter_contexts_len;
+}
+
+int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->file_contexts, data, len))
+ return -1;
+
+ p->file_contexts_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_seusers(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->seusers, data, len))
+ return -1;
+
+ p->seusers_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_user_extra(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->user_extra, data, len))
+ return -1;
+
+ p->user_extra_len = len;
+ return 0;
+}
+
+int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
+ char *data, size_t len)
+{
+ if (set_char(&p->netfilter_contexts, data, len))
+ return -1;
+
+ p->netfilter_contexts_len = len;
+ return 0;
+}
+
+sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
+{
+ return p->policy;
+}
+
+/* Append each of the file contexts from each module to the base
+ * policy's file context. 'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_fc_len' is the length of base's file context; it
+ * too is a reference variable. Return 0 on success, -1 if out of
+ * memory. */
+static int link_file_contexts(sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules)
+{
+ size_t fc_len;
+ int i;
+ char *s;
+
+ fc_len = base->file_contexts_len;
+ for (i = 0; i < num_modules; i++) {
+ fc_len += modules[i]->file_contexts_len;
+ }
+
+ if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
+ return -1;
+ }
+ base->file_contexts = s;
+ for (i = 0; i < num_modules; i++) {
+ memcpy(base->file_contexts + base->file_contexts_len,
+ modules[i]->file_contexts,
+ modules[i]->file_contexts_len);
+ base->file_contexts_len += modules[i]->file_contexts_len;
+ }
+ return 0;
+}
+
+/* Append each of the netfilter contexts from each module to the base
+ * policy's netfilter context. 'base_context' will be reallocated to a
+ * larger size (and thus it is an in/out reference
+ * variable). 'base_nc_len' is the length of base's netfilter contexts; it
+ * too is a reference variable. Return 0 on success, -1 if out of
+ * memory. */
+static int link_netfilter_contexts(sepol_module_package_t * base,
+ sepol_module_package_t ** modules,
+ int num_modules)
+{
+ size_t base_nc_len;
+ int i;
+ char *base_context;
+
+ base_nc_len = base->netfilter_contexts_len;
+ for (i = 0; i < num_modules; i++) {
+ base_nc_len += modules[i]->netfilter_contexts_len;
+ }
+
+ if ((base_context =
+ (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
+ return -1;
+ }
+ base->netfilter_contexts = base_context;
+ for (i = 0; i < num_modules; i++) {
+ memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
+ modules[i]->netfilter_contexts,
+ modules[i]->netfilter_contexts_len);
+ base->netfilter_contexts_len +=
+ modules[i]->netfilter_contexts_len;
+ }
+ return 0;
+}
+
+/* Links the module packages into the base. Returns 0 on success, -1
+ * if a requirement was not met, or -2 for all other errors. */
+int sepol_link_packages(sepol_handle_t * handle,
+ sepol_module_package_t * base,
+ sepol_module_package_t ** modules, int num_modules,
+ int verbose)
+{
+ policydb_t **mod_pols = NULL;
+ int i, retval;
+
+ if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+ for (i = 0; i < num_modules; i++) {
+ mod_pols[i] = &modules[i]->policy->p;
+ }
+
+ retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
+ verbose);
+ free(mod_pols);
+ if (retval == -3) {
+ return -1;
+ } else if (retval < 0) {
+ return -2;
+ }
+
+ if (link_file_contexts(base, modules, num_modules) == -1) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+
+ if (link_netfilter_contexts(base, modules, num_modules) == -1) {
+ ERR(handle, "Out of memory!");
+ return -2;
+ }
+
+ return 0;
+}
+
+/* buf must be large enough - no checks are performed */
+#define _read_helper_bufsize BUFSIZ
+static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
+{
+ uint32_t offset, nel, read_len;
+ int rc;
+
+ offset = 0;
+ nel = bytes;
+
+ while (nel) {
+ if (nel < _read_helper_bufsize)
+ read_len = nel;
+ else
+ read_len = _read_helper_bufsize;
+ rc = next_entry(&buf[offset], file, read_len);
+ if (rc < 0)
+ return -1;
+ offset += read_len;
+ nel -= read_len;
+ }
+ return 0;
+}
+
+#define MAXSECTIONS 100
+
+/* Get the section offsets from a package file, offsets will be malloc'd to
+ * the appropriate size and the caller must free() them */
+static int module_package_read_offsets(sepol_module_package_t * mod,
+ struct policy_file *file,
+ size_t ** offsets, uint32_t * sections)
+{
+ uint32_t *buf = NULL, nsec;
+ unsigned i;
+ size_t *off = NULL;
+ int rc;
+
+ buf = malloc(sizeof(uint32_t)*3);
+ if (!buf) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+
+ rc = next_entry(buf, file, sizeof(uint32_t) * 3);
+ if (rc < 0) {
+ ERR(file->handle, "module package header truncated");
+ goto err;
+ }
+ if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
+ ERR(file->handle,
+ "wrong magic number for module package: expected %#08x, got %#08x",
+ SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
+ goto err;
+ }
+
+ mod->version = le32_to_cpu(buf[1]);
+ nsec = *sections = le32_to_cpu(buf[2]);
+
+ if (nsec > MAXSECTIONS) {
+ ERR(file->handle, "too many sections (%u) in module package",
+ nsec);
+ goto err;
+ }
+
+ off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
+ if (!off) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+
+ free(buf);
+ buf = malloc(sizeof(uint32_t) * nsec);
+ if (!buf) {
+ ERR(file->handle, "out of memory");
+ goto err;
+ }
+ rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
+ if (rc < 0) {
+ ERR(file->handle, "module package offset array truncated");
+ goto err;
+ }
+
+ for (i = 0; i < nsec; i++) {
+ off[i] = le32_to_cpu(buf[i]);
+ if (i && off[i] < off[i - 1]) {
+ ERR(file->handle, "offsets are not increasing (at %u, "
+ "offset %zu -> %zu", i, off[i - 1],
+ off[i]);
+ goto err;
+ }
+ }
+
+ rc = policy_file_length(file, &off[nsec]);
+ if (rc < 0)
+ goto err;
+
+ if (nsec && off[nsec] < off[nsec-1]) {
+ ERR(file->handle, "offset greater than file size (at %u, "
+ "offset %zu -> %zu", nsec, off[nsec - 1],
+ off[nsec]);
+ goto err;
+ }
+ *offsets = off;
+ free(buf);
+ return 0;
+
+err:
+ free(buf);
+ free(off);
+ return -1;
+}
+
+/* Flags for which sections have been seen during parsing of module package. */
+#define SEEN_MOD 1
+#define SEEN_FC 2
+#define SEEN_SEUSER 4
+#define SEEN_USER_EXTRA 8
+#define SEEN_NETFILTER 16
+
+int sepol_module_package_read(sepol_module_package_t * mod,
+ struct sepol_policy_file *spf, int verbose)
+{
+ struct policy_file *file = &spf->pf;
+ uint32_t buf[1], nsec;
+ size_t *offsets, len;
+ int rc;
+ unsigned i, seen = 0;
+
+ if (module_package_read_offsets(mod, file, &offsets, &nsec))
+ return -1;
+
+ /* we know the section offsets, seek to them and read in the data */
+
+ for (i = 0; i < nsec; i++) {
+
+ if (policy_file_seek(file, offsets[i])) {
+ ERR(file->handle, "error seeking to offset %zu for "
+ "module package section %u", offsets[i], i);
+ goto cleanup;
+ }
+
+ len = offsets[i + 1] - offsets[i];
+
+ if (len < sizeof(uint32_t)) {
+ ERR(file->handle, "module package section %u "
+ "has too small length %zu", i, len);
+ goto cleanup;
+ }
+
+ /* read the magic number, so that we know which function to call */
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "module package section %u truncated, lacks magic number",
+ i);
+ goto cleanup;
+ }
+
+ switch (le32_to_cpu(buf[0])) {
+ case SEPOL_PACKAGE_SECTION_FC:
+ if (seen & SEEN_FC) {
+ ERR(file->handle,
+ "found multiple file contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->file_contexts_len = len - sizeof(uint32_t);
+ mod->file_contexts =
+ (char *)malloc(mod->file_contexts_len);
+ if (!mod->file_contexts) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->file_contexts, file,
+ mod->file_contexts_len)) {
+ ERR(file->handle,
+ "invalid file contexts section at section %u",
+ i);
+ free(mod->file_contexts);
+ mod->file_contexts = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_FC;
+ break;
+ case SEPOL_PACKAGE_SECTION_SEUSER:
+ if (seen & SEEN_SEUSER) {
+ ERR(file->handle,
+ "found multiple seuser sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->seusers_len = len - sizeof(uint32_t);
+ mod->seusers = (char *)malloc(mod->seusers_len);
+ if (!mod->seusers) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper(mod->seusers, file, mod->seusers_len)) {
+ ERR(file->handle,
+ "invalid seuser section at section %u", i);
+ free(mod->seusers);
+ mod->seusers = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_SEUSER;
+ break;
+ case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+ if (seen & SEEN_USER_EXTRA) {
+ ERR(file->handle,
+ "found multiple user_extra sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->user_extra_len = len - sizeof(uint32_t);
+ mod->user_extra = (char *)malloc(mod->user_extra_len);
+ if (!mod->user_extra) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->user_extra, file, mod->user_extra_len)) {
+ ERR(file->handle,
+ "invalid user_extra section at section %u",
+ i);
+ free(mod->user_extra);
+ mod->user_extra = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_USER_EXTRA;
+ break;
+ case SEPOL_PACKAGE_SECTION_NETFILTER:
+ if (seen & SEEN_NETFILTER) {
+ ERR(file->handle,
+ "found multiple netfilter contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ mod->netfilter_contexts_len = len - sizeof(uint32_t);
+ mod->netfilter_contexts =
+ (char *)malloc(mod->netfilter_contexts_len);
+ if (!mod->netfilter_contexts) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ if (read_helper
+ (mod->netfilter_contexts, file,
+ mod->netfilter_contexts_len)) {
+ ERR(file->handle,
+ "invalid netfilter contexts section at section %u",
+ i);
+ free(mod->netfilter_contexts);
+ mod->netfilter_contexts = NULL;
+ goto cleanup;
+ }
+ seen |= SEEN_NETFILTER;
+ break;
+ case POLICYDB_MOD_MAGIC:
+ if (seen & SEEN_MOD) {
+ ERR(file->handle,
+ "found multiple module sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ /* seek back to where the magic number was */
+ if (policy_file_seek(file, offsets[i]))
+ goto cleanup;
+
+ rc = policydb_read(&mod->policy->p, file, verbose);
+ if (rc < 0) {
+ ERR(file->handle,
+ "invalid module in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_MOD;
+ break;
+ default:
+ /* unknown section, ignore */
+ ERR(file->handle,
+ "unknown magic number at section %u, offset: %zx, number: %ux ",
+ i, offsets[i], le32_to_cpu(buf[0]));
+ break;
+ }
+ }
+
+ if ((seen & SEEN_MOD) == 0) {
+ ERR(file->handle, "missing module in module package");
+ goto cleanup;
+ }
+
+ free(offsets);
+ return 0;
+
+ cleanup:
+ free(offsets);
+ return -1;
+}
+
+int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
+ char **name, char **version)
+{
+ struct policy_file *file = &spf->pf;
+ sepol_module_package_t *mod = NULL;
+ uint32_t buf[5], len, nsec;
+ size_t *offsets = NULL;
+ unsigned i, seen = 0;
+ char *id;
+ int rc;
+
+ if (sepol_module_package_create(&mod))
+ return -1;
+
+ if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < nsec; i++) {
+
+ if (policy_file_seek(file, offsets[i])) {
+ ERR(file->handle, "error seeking to offset "
+ "%zu for module package section %u", offsets[i], i);
+ goto cleanup;
+ }
+
+ len = offsets[i + 1] - offsets[i];
+
+ if (len < sizeof(uint32_t)) {
+ ERR(file->handle,
+ "module package section %u has too small length %u",
+ i, len);
+ goto cleanup;
+ }
+
+ /* read the magic number, so that we know which function to call */
+ rc = next_entry(buf, file, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(file->handle,
+ "module package section %u truncated, lacks magic number",
+ i);
+ goto cleanup;
+ }
+
+ switch (le32_to_cpu(buf[0])) {
+ case SEPOL_PACKAGE_SECTION_FC:
+ /* skip file contexts */
+ if (seen & SEEN_FC) {
+ ERR(file->handle,
+ "found multiple file contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_FC;
+ break;
+ case SEPOL_PACKAGE_SECTION_SEUSER:
+ /* skip seuser */
+ if (seen & SEEN_SEUSER) {
+ ERR(file->handle,
+ "found seuser sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_SEUSER;
+ break;
+ case SEPOL_PACKAGE_SECTION_USER_EXTRA:
+ /* skip user_extra */
+ if (seen & SEEN_USER_EXTRA) {
+ ERR(file->handle,
+ "found user_extra sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_USER_EXTRA;
+ break;
+ case SEPOL_PACKAGE_SECTION_NETFILTER:
+ /* skip netfilter contexts */
+ if (seen & SEEN_NETFILTER) {
+ ERR(file->handle,
+ "found multiple netfilter contexts sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ seen |= SEEN_NETFILTER;
+ break;
+ case POLICYDB_MOD_MAGIC:
+ if (seen & SEEN_MOD) {
+ ERR(file->handle,
+ "found multiple module sections in module package (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[1]);
+ if (len != strlen(POLICYDB_MOD_STRING)) {
+ ERR(file->handle,
+ "module string length is wrong (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ /* skip id */
+ id = malloc(len + 1);
+ if (!id) {
+ ERR(file->handle,
+ "out of memory (at section %u)",
+ i);
+ goto cleanup;
+ }
+ rc = next_entry(id, file, len);
+ free(id);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module string (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ rc = next_entry(buf, file, sizeof(uint32_t) * 5);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module header (at section %u)",
+ i);
+ goto cleanup;
+ }
+
+ *type = le32_to_cpu(buf[0]);
+ /* if base - we're done */
+ if (*type == POLICY_BASE) {
+ *name = NULL;
+ *version = NULL;
+ seen |= SEEN_MOD;
+ break;
+ } else if (*type != POLICY_MOD) {
+ ERR(file->handle,
+ "module has invalid type %d (at section %u)",
+ *type, i);
+ goto cleanup;
+ }
+
+ /* read the name and version */
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module name len (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[0]);
+ *name = malloc(len + 1);
+ if (!*name) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ rc = next_entry(*name, file, len);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module name string (at section %u)",
+ i);
+ goto cleanup;
+ }
+ (*name)[len] = '\0';
+ rc = next_entry(buf, file, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module version len (at section %u)",
+ i);
+ goto cleanup;
+ }
+ len = le32_to_cpu(buf[0]);
+ *version = malloc(len + 1);
+ if (!*version) {
+ ERR(file->handle, "out of memory");
+ goto cleanup;
+ }
+ rc = next_entry(*version, file, len);
+ if (rc < 0) {
+ ERR(file->handle,
+ "cannot get module version string (at section %u)",
+ i);
+ goto cleanup;
+ }
+ (*version)[len] = '\0';
+ seen |= SEEN_MOD;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ if ((seen & SEEN_MOD) == 0) {
+ ERR(file->handle, "missing module in module package");
+ goto cleanup;
+ }
+
+ sepol_module_package_free(mod);
+ free(offsets);
+ return 0;
+
+ cleanup:
+ sepol_module_package_free(mod);
+ free(offsets);
+ return -1;
+}
+
+static int write_helper(char *data, size_t len, struct policy_file *file)
+{
+ int idx = 0;
+ size_t len2;
+
+ while (len) {
+ if (len > BUFSIZ)
+ len2 = BUFSIZ;
+ else
+ len2 = len;
+
+ if (put_entry(&data[idx], 1, len2, file) != len2) {
+ return -1;
+ }
+ len -= len2;
+ idx += len2;
+ }
+ return 0;
+}
+
+int sepol_module_package_write(sepol_module_package_t * p,
+ struct sepol_policy_file *spf)
+{
+ struct policy_file *file = &spf->pf;
+ policy_file_t polfile;
+ uint32_t buf[5], offsets[5], len, nsec = 0;
+ int i;
+
+ if (p->policy) {
+ /* compute policy length */
+ policy_file_init(&polfile);
+ polfile.type = PF_LEN;
+ polfile.handle = file->handle;
+ if (policydb_write(&p->policy->p, &polfile))
+ return -1;
+ len = polfile.len;
+ if (!polfile.len)
+ return -1;
+ nsec++;
+
+ } else {
+ /* We don't support writing a package without a module at this point */
+ return -1;
+ }
+
+ /* seusers and user_extra only supported in base at the moment */
+ if ((p->seusers || p->user_extra)
+ && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
+ ERR(file->handle,
+ "seuser and user_extra sections only supported in base");
+ return -1;
+ }
+
+ if (p->file_contexts)
+ nsec++;
+
+ if (p->seusers)
+ nsec++;
+
+ if (p->user_extra)
+ nsec++;
+
+ if (p->netfilter_contexts)
+ nsec++;
+
+ buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
+ buf[1] = cpu_to_le32(p->version);
+ buf[2] = cpu_to_le32(nsec);
+ if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
+ return -1;
+
+ /* calculate offsets */
+ offsets[0] = (nsec + 3) * sizeof(uint32_t);
+ buf[0] = cpu_to_le32(offsets[0]);
+
+ i = 1;
+ if (p->file_contexts) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ /* add a uint32_t to compensate for the magic number */
+ len = p->file_contexts_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->seusers) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->seusers_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->user_extra) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->user_extra_len + sizeof(uint32_t);
+ i++;
+ }
+ if (p->netfilter_contexts) {
+ offsets[i] = offsets[i - 1] + len;
+ buf[i] = cpu_to_le32(offsets[i]);
+ len = p->netfilter_contexts_len + sizeof(uint32_t);
+ i++;
+ }
+ if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
+ return -1;
+
+ /* write sections */
+
+ if (policydb_write(&p->policy->p, file))
+ return -1;
+
+ if (p->file_contexts) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->file_contexts, p->file_contexts_len, file))
+ return -1;
+ }
+ if (p->seusers) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->seusers, p->seusers_len, file))
+ return -1;
+
+ }
+ if (p->user_extra) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper(p->user_extra, p->user_extra_len, file))
+ return -1;
+ }
+ if (p->netfilter_contexts) {
+ buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
+ if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
+ return -1;
+ if (write_helper
+ (p->netfilter_contexts, p->netfilter_contexts_len, file))
+ return -1;
+ }
+ return 0;
+}
+
+int sepol_link_modules(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t ** modules, size_t len, int verbose)
+{
+ return link_modules(handle, &base->p, (policydb_t **) modules, len,
+ verbose);
+}
+
+int sepol_expand_module(sepol_handle_t * handle,
+ sepol_policydb_t * base,
+ sepol_policydb_t * out, int verbose, int check)
+{
+ return expand_module(handle, &base->p, &out->p, verbose, check);
+}
diff --git a/libsepol/src/module_internal.h b/libsepol/src/module_internal.h
new file mode 100644
index 0000000..cdd5ec6
--- /dev/null
+++ b/libsepol/src/module_internal.h
@@ -0,0 +1,5 @@
+#include <sepol/module.h>
+#include "dso.h"
+
+hidden_proto(sepol_module_package_create)
+ hidden_proto(sepol_module_package_free)
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
new file mode 100644
index 0000000..b9a4af7
--- /dev/null
+++ b/libsepol/src/module_to_cil.c
@@ -0,0 +1,4097 @@
+/* Authors: Steve Lawrence <slawrence@tresys.com>
+ *
+ * Functions to convert policy module to CIL
+ *
+ * Copyright (C) 2015 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sepol/module.h>
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/util.h>
+
+#ifdef __GNUC__
+# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+# define UNUSED(x) UNUSED_ ## x
+#endif
+
+FILE *out_file;
+
+#define STACK_SIZE 16
+#define DEFAULT_LEVEL "systemlow"
+#define DEFAULT_OBJECT "object_r"
+#define GEN_REQUIRE_ATTR "cil_gen_require"
+
+__attribute__ ((format(printf, 1, 2)))
+static void log_err(const char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(stderr, fmt, argptr) < 0) {
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+ if (fprintf(stderr, "\n") < 0) {
+ _exit(EXIT_FAILURE);
+ }
+}
+
+static void cil_indent(int indent)
+{
+ if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+}
+
+__attribute__ ((format(printf, 1, 2)))
+static void cil_printf(const char *fmt, ...) {
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(out_file, fmt, argptr) < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void cil_println(int indent, const char *fmt, ...)
+{
+ cil_indent(indent);
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(out_file, fmt, argptr) < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+ if (fprintf(out_file, "\n") < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+}
+
+static int get_line(char **start, char *end, char **line)
+{
+ int rc = 1;
+ char *p = NULL;
+ size_t len = 0;
+
+ *line = NULL;
+
+ for (p = *start; p < end && isspace(*p); p++);
+
+ *start = p;
+
+ for (len = 0; p < end && *p != '\n' && *p != '\0'; p++, len++);
+
+ if (len == 0) {
+ rc = 0;
+ goto exit;
+ }
+
+ *line = malloc(len+1);
+ if (*line == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ memcpy(*line, *start, len);
+ (*line)[len] = '\0';
+
+ *start = p;
+
+ return rc;
+
+exit:
+ *start = NULL;
+ return rc;
+}
+
+struct map_args {
+ struct policydb *pdb;
+ struct avrule_block *block;
+ struct stack *decl_stack;
+ int scope;
+ int indent;
+ int sym_index;
+};
+
+struct stack {
+ void **stack;
+ int pos;
+ int size;
+};
+
+struct role_list_node {
+ char *role_name;
+ role_datum_t *role;
+};
+
+struct attr_list_node {
+ char *attribute;
+ int is_type;
+ union {
+ struct type_set *ts;
+ struct role_set *rs;
+ } set;
+};
+
+struct list_node {
+ void *data;
+ struct list_node *next;
+};
+
+struct list {
+ struct list_node *head;
+};
+
+/* A linked list of all roles stored in the pdb
+ * which is iterated to determine types associated
+ * with each role when printing role_type statements
+ */
+static struct list *role_list;
+
+static void list_destroy(struct list **list)
+{
+ struct list_node *curr = (*list)->head;
+ struct list_node *tmp;
+
+ while (curr != NULL) {
+ tmp = curr->next;
+ free(curr);
+ curr = tmp;
+ }
+
+ free(*list);
+ *list = NULL;
+}
+
+static void role_list_destroy(void)
+{
+ struct list_node *curr = role_list->head;
+
+ while (curr != NULL) {
+ free(curr->data);
+ curr->data = NULL;
+ curr = curr->next;
+ }
+
+ list_destroy(&role_list);
+}
+
+static void attr_list_destroy(struct list **attr_list)
+{
+ if (attr_list == NULL || *attr_list == NULL) {
+ return;
+ }
+
+ struct list_node *curr = (*attr_list)->head;
+ struct attr_list_node *attr;
+
+ while (curr != NULL) {
+ attr = curr->data;
+ if (attr != NULL) {
+ free(attr->attribute);
+ }
+
+ free(curr->data);
+ curr->data = NULL;
+ curr = curr->next;
+ }
+
+ list_destroy(attr_list);
+}
+
+static int list_init(struct list **list)
+{
+ int rc = -1;
+ struct list *l = calloc(1, sizeof(*l));
+ if (l == NULL) {
+ goto exit;
+ }
+
+ *list = l;
+
+ return 0;
+
+exit:
+ list_destroy(&l);
+ return rc;
+}
+
+static int list_prepend(struct list *list, void *data)
+{
+ int rc = -1;
+ struct list_node *node = calloc(1, sizeof(*node));
+ if (node == NULL) {
+ goto exit;
+ }
+
+ node->data = data;
+ node->next = list->head;
+ list->head = node;
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int roles_gather_map(char *key, void *data, void *args)
+{
+ struct role_list_node *role_node;
+ role_datum_t *role = data;
+ int rc = -1;
+
+ role_node = calloc(1, sizeof(*role_node));
+ if (role_node == NULL) {
+ return rc;
+ }
+
+ role_node->role_name = key;
+ role_node->role = role;
+
+ rc = list_prepend((struct list *)args, role_node);
+ return rc;
+}
+
+static int role_list_create(hashtab_t roles_tab)
+{
+ int rc = -1;
+
+ rc = list_init(&role_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = hashtab_map(roles_tab, roles_gather_map, role_list);
+
+exit:
+ return rc;
+}
+
+// array of lists, where each list contains all the aliases defined in the scope at index i
+static struct list **typealias_lists;
+static uint32_t typealias_lists_len;
+
+static int typealiases_gather_map(char *key, void *data, void *arg)
+{
+ int rc = -1;
+ struct type_datum *type = data;
+ struct policydb *pdb = arg;
+ struct scope_datum *scope;
+ uint32_t i;
+ uint32_t scope_id;
+
+ if (type->primary != 1) {
+ scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
+ if (scope == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ scope_id = scope->decl_ids[i];
+ if (typealias_lists[scope_id] == NULL) {
+ rc = list_init(&typealias_lists[scope_id]);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ list_prepend(typealias_lists[scope_id], key);
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static void typealias_list_destroy(void)
+{
+ uint32_t i;
+ for (i = 0; i < typealias_lists_len; i++) {
+ if (typealias_lists[i] != NULL) {
+ list_destroy(&typealias_lists[i]);
+ }
+ }
+ typealias_lists_len = 0;
+ free(typealias_lists);
+ typealias_lists = NULL;
+}
+
+static int typealias_list_create(struct policydb *pdb)
+{
+ uint32_t max_decl_id = 0;
+ struct avrule_decl *decl;
+ struct avrule_block *block;
+ uint32_t rc = -1;
+
+ for (block = pdb->global; block != NULL; block = block->next) {
+ decl = block->branch_list;
+ if (decl->decl_id > max_decl_id) {
+ max_decl_id = decl->decl_id;
+ }
+ }
+
+ typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
+ typealias_lists_len = max_decl_id + 1;
+
+ rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ typealias_list_destroy();
+
+ return rc;
+}
+
+
+static int stack_destroy(struct stack **stack)
+{
+ if (stack == NULL || *stack == NULL) {
+ return 0;
+ }
+
+ free((*stack)->stack);
+ free(*stack);
+ *stack = NULL;
+
+ return 0;
+}
+
+static int stack_init(struct stack **stack)
+{
+ int rc = -1;
+ struct stack *s = calloc(1, sizeof(*s));
+ if (s == NULL) {
+ goto exit;
+ }
+
+ s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
+ if (s->stack == NULL) {
+ goto exit;
+ }
+
+ s->pos = -1;
+ s->size = STACK_SIZE;
+
+ *stack = s;
+
+ return 0;
+
+exit:
+ stack_destroy(&s);
+ return rc;
+}
+
+static int stack_push(struct stack *stack, void *ptr)
+{
+ int rc = -1;
+ void *new_stack;
+
+ if (stack->pos + 1 == stack->size) {
+ new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
+ if (new_stack == NULL) {
+ goto exit;
+ }
+ stack->stack = new_stack;
+ stack->size *= 2;
+ }
+
+ stack->pos++;
+ stack->stack[stack->pos] = ptr;
+
+ rc = 0;
+exit:
+ return rc;
+}
+
+static void *stack_pop(struct stack *stack)
+{
+ if (stack->pos == -1) {
+ return NULL;
+ }
+
+ stack->pos--;
+ return stack->stack[stack->pos + 1];
+}
+
+static void *stack_peek(struct stack *stack)
+{
+ if (stack->pos == -1) {
+ return NULL;
+ }
+
+ return stack->stack[stack->pos];
+}
+
+static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
+{
+ int i;
+ uint32_t j;
+ struct avrule_decl *decl;
+ struct scope_datum *scope;
+
+ scope = hashtab_search(pdb->scope[symbol_type].table, id);
+ if (scope == NULL) {
+ return 0;
+ }
+
+ for (i = start; i >= 0; i--) {
+ decl = decl_stack->stack[i];
+
+ for (j = 0; j < scope->decl_ids_len; j++) {
+ if (scope->decl_ids[j] == decl->decl_id) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+ int start = decl_stack->pos - 1;
+
+ return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+ int start = decl_stack->pos;
+
+ return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
+{
+ struct mls_semantic_cat *cat;
+
+ cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
+
+ if (level->cat != NULL) {
+ cil_printf("(");
+ }
+
+ for (cat = level->cat; cat != NULL; cat = cat->next) {
+ if (cat->low == cat->high) {
+ cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
+ } else {
+ cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
+ }
+
+ if (cat->next != NULL) {
+ cil_printf(" ");
+ }
+ }
+
+ if (level->cat != NULL) {
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ return 0;
+}
+
+static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
+{
+ int rc = -1;
+ const char *rule;
+ const struct class_perm_node *classperm;
+ char *perms;
+
+ switch (type) {
+ case AVRULE_ALLOWED:
+ rule = "allow";
+ break;
+ case AVRULE_AUDITALLOW:
+ rule = "auditallow";
+ break;
+ case AVRULE_AUDITDENY:
+ rule = "auditdenty";
+ break;
+ case AVRULE_DONTAUDIT:
+ rule = "dontaudit";
+ break;
+ case AVRULE_NEVERALLOW:
+ rule = "neverallow";
+ break;
+ case AVRULE_TRANSITION:
+ rule = "typetransition";
+ break;
+ case AVRULE_MEMBER:
+ rule = "typemember";
+ break;
+ case AVRULE_CHANGE:
+ rule = "typechange";
+ break;
+ default:
+ log_err("Unknown avrule type: %i", type);
+ rc = -1;
+ goto exit;
+ }
+
+ for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
+ if (type & AVRULE_AV) {
+ perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
+ if (perms == NULL) {
+ log_err("Failed to generate permission string");
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(%s %s %s (%s (%s)))",
+ rule, src, tgt,
+ pdb->p_class_val_to_name[classperm->tclass - 1],
+ perms + 1);
+ } else {
+ cil_println(indent, "(%s %s %s %s %s)",
+ rule, src, tgt,
+ pdb->p_class_val_to_name[classperm->tclass - 1],
+ pdb->p_type_val_to_name[classperm->data - 1]);
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int num_digits(int n)
+{
+ int num = 1;
+ while (n >= 10) {
+ n /= 10;
+ num++;
+ }
+ return num;
+}
+
+static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
+{
+ static unsigned int num_attrs = 0;
+ int rc = -1;
+ int len, rlen;
+ const char *attr_infix;
+ char *attr;
+
+ num_attrs++;
+
+ if (is_type) {
+ attr_infix = "_typeattr_";
+ } else {
+ attr_infix = "_roleattr_";
+ }
+
+ len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
+ attr = malloc(len);
+ if (attr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate attribute name");
+ rc = -1;
+ goto exit;
+ }
+
+ *names = malloc(sizeof(**names));
+ if (*names == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+
+ *names[0] = attr;
+ *num_names = 1;
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
+{
+ // CIL doesn't support anonymous positive/negative/complemented sets. So
+ // instead we create a CIL type/roleattributeset that matches the set. If
+ // the set has a negative set, then convert it to is (P & !N), where P is
+ // the list of members in the positive set , and N is the list of members
+ // in the negative set. Additonally, if the set is complemented, then wrap
+ // the whole thing with a negation.
+
+ int rc = 0;
+ struct ebitmap_node *node;
+ unsigned int i;
+ char *statement;
+ int has_positive = pos && (ebitmap_cardinality(pos) > 0);
+ int has_negative = neg && (ebitmap_cardinality(neg) > 0);
+ char **val_to_name;
+
+ if (is_type) {
+ statement = "type";
+ val_to_name = pdb->p_type_val_to_name;
+ } else {
+ statement = "role";
+ val_to_name = pdb->p_role_val_to_name;
+ }
+
+ cil_println(indent, "(%sattribute %s)", statement, attr);
+ cil_indent(indent);
+ cil_printf("(%sattributeset %s ", statement, attr);
+
+ if (flags & TYPE_STAR) {
+ cil_printf("(all)");
+ }
+
+ if (flags & TYPE_COMP) {
+ cil_printf("(not ");
+ }
+
+ if (has_positive && has_negative) {
+ cil_printf("(and ");
+ }
+
+ if (has_positive) {
+ cil_printf("(");
+ ebitmap_for_each_bit(pos, node, i) {
+ if (!ebitmap_get_bit(pos, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+ cil_printf(") ");
+ }
+
+ if (has_negative) {
+ cil_printf("(not (");
+
+ ebitmap_for_each_bit(neg, node, i) {
+ if (!ebitmap_get_bit(neg, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+
+ cil_printf("))");
+ }
+
+ if (has_positive && has_negative) {
+ cil_printf(")");
+ }
+
+ if (flags & TYPE_COMP) {
+ cil_printf(")");
+ }
+
+ cil_printf(")\n");
+
+ return rc;
+}
+
+static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+ char **val_to_name = pdb->sym_val_to_name[type];
+
+ ebitmap_for_each_bit(map, node, i) {
+ if (!ebitmap_get_bit(map, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+
+ return 0;
+}
+
+static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+ uint32_t num = 0;
+ uint32_t max = 8;
+ char **name_arr = NULL;
+
+ name_arr = malloc(sizeof(*name_arr) * max);
+ if (name_arr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+
+ if (num + 1 == max) {
+ max *= 2;
+ name_arr = realloc(name_arr, sizeof(*name_arr) * max);
+ if (name_arr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+
+ name_arr[num] = strdup(vals_to_names[i]);
+ if (name_arr[num] == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ num++;
+ }
+
+ *names = name_arr;
+ *num_names = num;
+
+ return 0;
+
+exit:
+ for (i = 0; i < num; i++) {
+ free(name_arr[i]);
+ }
+ free(name_arr);
+ return rc;
+}
+
+static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
+{
+ struct attr_list_node *attr_list_node = NULL;
+ int rc = -1;
+
+ attr_list_node = calloc(1, sizeof(*attr_list_node));
+ if (attr_list_node == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = list_prepend(attr_list, attr_list_node);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ attr_list_node->attribute = strdup(attribute);
+ if (attr_list_node->attribute == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ attr_list_node->is_type = is_type;
+ if (is_type) {
+ attr_list_node->set.ts = set;
+ } else {
+ attr_list_node->set.rs = set;
+ }
+
+ return rc;
+
+exit:
+ if (attr_list_node != NULL) {
+ free(attr_list_node->attribute);
+ }
+ free(attr_list_node);
+ return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+ int rc = -1;
+ if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
+ rc = set_to_cil_attr(pdb, 1, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ *generated_attribute = *names[0];
+ } else {
+ rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+ int rc = -1;
+ if (rs->flags != 0) {
+ rc = set_to_cil_attr(pdb, 0, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ *generated_attribute = *names[0];
+ } else {
+ rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+ int rc = -1;
+ char *generated_attribute = NULL;
+ *num_type_names = 0;
+
+ rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (generated_attribute == NULL) {
+ goto exit;
+ }
+
+ if (attr_list == NULL) {
+ rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else {
+ rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+ int rc = -1;
+ char *generated_attribute = NULL;
+ *num_type_names = 0;
+
+ rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (generated_attribute == NULL) {
+ rc = 0;
+ goto exit;
+ }
+
+ if (attr_list == NULL) {
+ rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else {
+ rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static void names_destroy(char ***names, uint32_t *num_names)
+{
+ char **arr = *names;
+ uint32_t num = *num_names;
+ uint32_t i;
+
+ for (i = 0; i < num; i++) {
+ free(arr[i]);
+ arr[i] = NULL;
+ }
+ free(arr);
+
+ *names = NULL;
+ *num_names = 0;
+}
+
+static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
+{
+ struct list_node *curr;
+ char **tnames = NULL;
+ uint32_t num_tnames, i;
+ struct role_list_node *role_node = NULL;
+ int rc;
+ struct type_set *ts;
+
+ curr = role_list->head;
+ for (curr = role_list->head; curr != NULL; curr = curr->next) {
+ role_node = curr->data;
+ if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
+ continue;
+ }
+
+ ts = &role_node->role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
+ if (rc != 0) {
+ goto exit;
+ }
+ for (i = 0; i < num_tnames; i++) {
+ if (!strcmp(type_name, tnames[i])) {
+ cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
+ }
+ }
+ names_destroy(&tnames, &num_tnames);
+ }
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+
+static int name_list_to_string(char **names, int num_names, char **string)
+{
+ // create a space separated string of the names
+ int rc = -1;
+ int len = 0;
+ int i;
+ char *str;
+ char *strpos;
+ int name_len;
+ int rlen;
+
+ for (i = 0; i < num_names; i++) {
+ len += strlen(names[i]);
+ }
+
+ // add spaces + null terminator
+ len += (num_names - 1) + 1;
+
+ str = malloc(len);
+ if (str == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ strpos = str;
+
+ for (i = 0; i < num_names; i++) {
+ name_len = strlen(names[i]);
+ rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate name list");
+ rc = -1;
+ goto exit;
+ }
+
+ if (i < num_names - 1) {
+ strpos[name_len] = ' ';
+ }
+ strpos += name_len + 1;
+ }
+
+ *string = str;
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
+{
+ int rc = -1;
+ struct avrule *avrule;
+ char **snames = NULL;
+ char **tnames = NULL;
+ uint32_t num_snames;
+ uint32_t num_tnames;
+ uint32_t s;
+ uint32_t t;
+ struct type_set *ts;
+
+ for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
+ if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) {
+ cil_println(0, ";;* lmx %lu %s\n",avrule->source_line, avrule->source_filename);
+ }
+
+ ts = &avrule->stypes;
+ rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &avrule->ttypes;
+ rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (s = 0; s < num_snames; s++) {
+ for (t = 0; t < num_tnames; t++) {
+ rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (avrule->flags & RULE_SELF) {
+ rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ names_destroy(&snames, &num_snames);
+ names_destroy(&tnames, &num_tnames);
+
+ if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) {
+ cil_println(0, ";;* lme\n");
+ }
+ }
+
+ return 0;
+
+exit:
+ names_destroy(&snames, &num_snames);
+ names_destroy(&tnames, &num_tnames);
+
+ return rc;
+}
+
+static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
+{
+ int rc = -1;
+ struct cond_expr *curr;
+ struct stack *stack = NULL;
+ int len = 0;
+ int rlen;
+ char *new_val = NULL;
+ char *val1 = NULL;
+ char *val2 = NULL;
+ int num_params;
+ const char *op;
+ const char *fmt_str;
+ const char *type;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+
+ for (curr = cond_expr; curr != NULL; curr = curr->next) {
+ if (curr->expr_type == COND_BOOL) {
+ val1 = pdb->p_bool_val_to_name[curr->bool - 1];
+ // length of boolean + 2 parens + null terminator
+ len = strlen(val1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s)", val1);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate conditional expression");
+ rc = -1;
+ goto exit;
+ }
+ num_params = 0;
+ } else {
+ switch(curr->expr_type) {
+ case COND_NOT: op = "not"; break;
+ case COND_OR: op = "or"; break;
+ case COND_AND: op = "and"; break;
+ case COND_XOR: op = "xor"; break;
+ case COND_EQ: op = "eq"; break;
+ case COND_NEQ: op = "neq"; break;
+ default:
+ rc = -1;
+ goto exit;
+ }
+
+ num_params = curr->expr_type == COND_NOT ? 1 : 2;
+
+ if (num_params == 1) {
+ val1 = stack_pop(stack);
+ val2 = strdup("");
+ if (val2 == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ fmt_str = "(%s %s)";
+ } else {
+ val2 = stack_pop(stack);
+ val1 = stack_pop(stack);
+ fmt_str = "(%s %s %s)";
+ }
+
+ if (val1 == NULL || val2 == NULL) {
+ log_err("Invalid conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ // length = length of parameters +
+ // length of operator +
+ // 1 space preceeding each parameter +
+ // 2 parens around the whole expression
+ // + null terminator
+ len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ // although we always supply val2 and there isn't always a 2nd
+ // value, it should only be used when there are actually two values
+ // in the format strings
+ rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ free(val1);
+ free(val2);
+ val1 = NULL;
+ val2 = NULL;
+ }
+
+ rc = stack_push(stack, new_val);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+ new_val = NULL;
+ }
+
+ if (flags & COND_NODE_FLAGS_TUNABLE) {
+ type = "tunableif";
+ } else {
+ type = "booleanif";
+ }
+
+ val1 = stack_pop(stack);
+ if (val1 == NULL || stack_peek(stack) != NULL) {
+ log_err("Invalid conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(indent, "(%s %s", type, val1);
+ free(val1);
+ val1 = NULL;
+
+ rc = 0;
+
+exit:
+ free(new_val);
+ free(val1);
+ free(val2);
+ while ((val1 = stack_pop(stack)) != NULL) {
+ free(val1);
+ }
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
+{
+ struct list_node *curr;
+ struct attr_list_node *attr_list_node;
+ int rc = 0;
+ struct type_set *ts;
+ struct role_set *rs;
+ char *generated_attribute;
+
+ for (curr = attr_list->head; curr != NULL; curr = curr->next) {
+ attr_list_node = curr->data;
+ generated_attribute = attr_list_node->attribute;
+ if (generated_attribute == NULL) {
+ return -1;
+ }
+
+ if (attr_list_node->is_type) {
+ ts = attr_list_node->set.ts;
+ rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+ if (rc != 0) {
+ return rc;
+ }
+ } else {
+ rs = attr_list_node->set.rs;
+ rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
+{
+ int rc = -1;
+ struct cond_node *cond;
+ struct list *attr_list;
+
+ rc = list_init(&attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (cond = cond_list; cond != NULL; cond = cond->next) {
+
+ rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (cond->avtrue_list != NULL) {
+ cil_println(indent + 1, "(true");
+ rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+ cil_println(indent + 1, ")");
+ }
+
+ if (cond->avfalse_list != NULL) {
+ cil_println(indent + 1, "(false");
+ rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+ cil_println(indent + 1, ")");
+ }
+
+ cil_println(indent, ")");
+ }
+
+ rc = cil_print_attr_list(indent, pdb, attr_list);
+
+exit:
+ attr_list_destroy(&attr_list);
+ return rc;
+}
+
+static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
+{
+ int rc = -1;
+ struct role_trans_rule *rule;
+ char **role_names = NULL;
+ uint32_t num_role_names = 0;
+ char **type_names = NULL;
+ uint32_t num_type_names = 0;
+ uint32_t type;
+ uint32_t role;
+ uint32_t i;
+ struct ebitmap_node *node;
+ struct type_set *ts;
+ struct role_set *rs;
+
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ rs = &rule->roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (role = 0; role < num_role_names; role++) {
+ for (type = 0; type < num_type_names; type++) {
+ ebitmap_for_each_bit(&rule->classes, node, i) {
+ if (!ebitmap_get_bit(&rule->classes, i)) {
+ continue;
+ }
+ cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
+ type_names[type],
+ pdb->p_class_val_to_name[i],
+ pdb->p_role_val_to_name[rule->new_role - 1]);
+ }
+ }
+ }
+
+ names_destroy(&role_names, &num_role_names);
+ names_destroy(&type_names, &num_type_names);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&role_names, &num_role_names);
+ names_destroy(&type_names, &num_type_names);
+
+ return rc;
+}
+
+static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
+{
+ int rc = -1;
+ struct role_allow_rule *rule;
+ char **roles = NULL;
+ uint32_t num_roles = 0;
+ char **new_roles = NULL;
+ uint32_t num_new_roles = 0;
+ uint32_t i;
+ uint32_t j;
+ struct role_set *rs;
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ rs = &rule->roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rs = &rule->new_roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < num_roles; i++) {
+ for (j = 0; j < num_new_roles; j++) {
+ cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
+ }
+ }
+
+ names_destroy(&roles, &num_roles);
+ names_destroy(&new_roles, &num_new_roles);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&roles, &num_roles);
+ names_destroy(&new_roles, &num_new_roles);
+
+ return rc;
+}
+
+static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
+{
+ int rc = -1;
+ struct range_trans_rule *rule;
+ char **stypes = NULL;
+ uint32_t num_stypes = 0;
+ char **ttypes = NULL;
+ uint32_t num_ttypes = 0;
+ struct ebitmap_node *node;
+ uint32_t i;
+ uint32_t stype;
+ uint32_t ttype;
+ struct type_set *ts;
+
+ if (!pdb->mls) {
+ return 0;
+ }
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ ts = &rule->stypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->ttypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (stype = 0; stype < num_stypes; stype++) {
+ for (ttype = 0; ttype < num_ttypes; ttype++) {
+ ebitmap_for_each_bit(&rule->tclasses, node, i) {
+ if (!ebitmap_get_bit(&rule->tclasses, i)) {
+ continue;
+ }
+
+ cil_indent(indent);
+ cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
+
+ cil_printf("(");
+
+ rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ cil_printf(" ");
+
+ rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ cil_printf("))\n");
+ }
+
+ }
+ }
+
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+
+ return rc;
+}
+
+static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
+{
+ int rc = -1;
+ char **stypes = NULL;
+ uint32_t num_stypes = 0;
+ char **ttypes = NULL;
+ uint32_t num_ttypes = 0;
+ uint32_t stype;
+ uint32_t ttype;
+ struct type_set *ts;
+
+ struct filename_trans_rule *rule;
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ ts = &rule->stypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->ttypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (stype = 0; stype < num_stypes; stype++) {
+ for (ttype = 0; ttype < num_ttypes; ttype++) {
+ cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
+ ttypes[ttype],
+ pdb->p_class_val_to_name[rule->tclass - 1],
+ rule->name,
+ pdb->p_type_val_to_name[rule->otype - 1]);
+ }
+ }
+
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+ }
+
+ rc = 0;
+exit:
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+
+ return rc;
+}
+
+struct class_perm_datum {
+ char *name;
+ uint32_t val;
+};
+
+struct class_perm_array {
+ struct class_perm_datum *perms;
+ uint32_t count;
+};
+
+static int class_perm_to_array(char *key, void *data, void *args)
+{
+ struct class_perm_array *arr = args;
+ struct perm_datum *datum = data;
+ arr->perms[arr->count].name = key;
+ arr->perms[arr->count].val = datum->s.value;
+ arr->count++;
+
+ return 0;
+}
+
+static int class_perm_cmp(const void *a, const void *b)
+{
+ const struct class_perm_datum *aa = a;
+ const struct class_perm_datum *bb = b;
+
+ return aa->val - bb->val;
+}
+
+static int common_to_cil(char *key, void *data, void *UNUSED(arg))
+{
+ int rc = -1;
+ struct common_datum *common = data;
+ struct class_perm_array arr;
+ uint32_t i;
+
+ arr.count = 0;
+ arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
+ rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+ cil_printf("(common %s (", key);
+ for (i = 0; i < arr.count; i++) {
+ cil_printf("%s ", arr.perms[i].name);
+ }
+ cil_printf("))\n");
+
+ rc = 0;
+
+exit:
+ free(arr.perms);
+ return rc;
+}
+
+
+static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
+{
+ int rc = -1;
+ struct constraint_expr *expr;
+ struct stack *stack = NULL;
+ int len = 0;
+ int rlen;
+ char *new_val = NULL;
+ char *val1 = NULL;
+ char *val2 = NULL;
+ uint32_t num_params;
+ const char *op;
+ const char *fmt_str;
+ const char *attr1;
+ const char *attr2;
+ char *names;
+ char **name_list = NULL;
+ uint32_t num_names = 0;
+ struct type_set *ts;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (expr = exprs; expr != NULL; expr = expr->next) {
+ if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
+ switch (expr->op) {
+ case CEXPR_EQ: op = "eq"; break;
+ case CEXPR_NEQ: op = "neq"; break;
+ case CEXPR_DOM: op = "dom"; break;
+ case CEXPR_DOMBY: op = "domby"; break;
+ case CEXPR_INCOMP: op = "incomp"; break;
+ default:
+ log_err("Unknown constraint operator type: %i", expr->op);
+ rc = -1;
+ goto exit;
+ }
+
+ switch (expr->attr) {
+ case CEXPR_USER: attr1 = "u1"; attr2 = "u2"; break;
+ case CEXPR_USER | CEXPR_TARGET: attr1 = "u2"; attr2 = ""; break;
+ case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = ""; break;
+ case CEXPR_ROLE: attr1 = "r1"; attr2 = "r2"; break;
+ case CEXPR_ROLE | CEXPR_TARGET: attr1 = "r2"; attr2 = ""; break;
+ case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = ""; break;
+ case CEXPR_TYPE: attr1 = "t1"; attr2 = ""; break;
+ case CEXPR_TYPE | CEXPR_TARGET: attr1 = "t2"; attr2 = ""; break;
+ case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = ""; break;
+ case CEXPR_L1L2: attr1 = "l1"; attr2 = "l2"; break;
+ case CEXPR_L1H2: attr1 = "l1"; attr2 = "h2"; break;
+ case CEXPR_H1L2: attr1 = "h1"; attr2 = "l2"; break;
+ case CEXPR_H1H2: attr1 = "h1"; attr2 = "h2"; break;
+ case CEXPR_L1H1: attr1 = "l1"; attr2 = "h1"; break;
+ case CEXPR_L2H2: attr1 = "l2"; attr2 = "h2"; break;
+ default:
+ log_err("Unknown expression attribute type: %i", expr->attr);
+ rc = -1;
+ goto exit;
+ }
+
+ if (expr->expr_type == CEXPR_ATTR) {
+ // length of values/attrs + 2 separating spaces + 2 parens + null terminator
+ len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+ } else {
+ if (expr->attr & CEXPR_TYPE) {
+ ts = expr->type_names;
+ rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else if (expr->attr & CEXPR_USER) {
+ rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else if (expr->attr & CEXPR_ROLE) {
+ rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ rc = name_list_to_string(name_list, num_names, &names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // length of values/oper + 2 spaces + 2 parens + null terminator
+ len = strlen(op) + strlen(attr1) + strlen(names) + 2 + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ names_destroy(&name_list, &num_names);
+ free(names);
+ }
+
+ num_params = 0;
+ } else {
+ switch (expr->expr_type) {
+ case CEXPR_NOT: op = "not"; break;
+ case CEXPR_AND: op = "and"; break;
+ case CEXPR_OR: op = "or"; break;
+ default:
+ log_err("Unknown constraint expression type: %i", expr->expr_type);
+ rc = -1;
+ goto exit;
+ }
+
+ num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
+
+ if (num_params == 1) {
+ val1 = stack_pop(stack);
+ val2 = strdup("");
+ if (val2 == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ fmt_str = "(%s %s)";
+ } else {
+ val2 = stack_pop(stack);
+ val1 = stack_pop(stack);
+ fmt_str = "(%s %s %s)";
+ }
+
+ if (val1 == NULL || val2 == NULL) {
+ log_err("Invalid constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ // length = length of parameters +
+ // length of operator +
+ // 1 space preceeding each parameter +
+ // 2 parens around the whole expression
+ // + null terminator
+ len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ // although we always supply val2 and there isn't always a 2nd
+ // value, it should only be used when there are actually two values
+ // in the format strings
+ rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ free(val1);
+ free(val2);
+ val1 = NULL;
+ val2 = NULL;
+ }
+
+ rc = stack_push(stack, new_val);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+
+ new_val = NULL;
+ }
+
+ new_val = stack_pop(stack);
+ if (new_val == NULL || stack_peek(stack) != NULL) {
+ log_err("Invalid constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ *expr_string = new_val;
+ new_val = NULL;
+
+ rc = 0;
+
+exit:
+ names_destroy(&name_list, &num_names);
+
+ free(new_val);
+ free(val1);
+ free(val2);
+ while ((val1 = stack_pop(stack)) != NULL) {
+ free(val1);
+ }
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+
+static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
+{
+ int rc = -1;
+ struct constraint_node *node;
+ char *expr = NULL;
+ const char *mls;
+ char *perms;
+
+ mls = pdb->mls ? "mls" : "";
+
+ for (node = constraints; node != NULL; node = node->next) {
+
+ rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (is_constraint) {
+ perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
+ cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
+ } else {
+ cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
+ }
+
+ free(expr);
+ expr = NULL;
+ }
+
+ rc = 0;
+
+exit:
+ free(expr);
+ return rc;
+}
+
+static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct class_datum *class = datum;
+ const char *dflt;
+ struct class_perm_array arr;
+ uint32_t i;
+
+ if (scope == SCOPE_REQ) {
+ return 0;
+ }
+
+ arr.count = 0;
+ arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
+ rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+ cil_indent(indent);
+ cil_printf("(class %s (", key);
+ for (i = 0; i < arr.count; i++) {
+ cil_printf("%s ", arr.perms[i].name);
+ }
+ cil_printf("))\n");
+
+ if (class->comkey != NULL) {
+ cil_println(indent, "(classcommon %s %s)", key, class->comkey);
+ }
+
+ if (class->default_user != 0) {
+ switch (class->default_user) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default user value: %i", class->default_user);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultuser %s %s)", key, dflt);
+ }
+
+ if (class->default_role != 0) {
+ switch (class->default_role) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default role value: %i", class->default_role);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultrole %s %s)", key, dflt);
+ }
+
+ if (class->default_type != 0) {
+ switch (class->default_type) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default type value: %i", class->default_type);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaulttype %s %s)", key, dflt);
+ }
+
+ if (class->default_range != 0) {
+ switch (class->default_range) {
+ case DEFAULT_SOURCE_LOW: dflt = "source low"; break;
+ case DEFAULT_SOURCE_HIGH: dflt = "source high"; break;
+ case DEFAULT_SOURCE_LOW_HIGH: dflt = "source low-high"; break;
+ case DEFAULT_TARGET_LOW: dflt = "target low"; break;
+ case DEFAULT_TARGET_HIGH: dflt = "target high"; break;
+ case DEFAULT_TARGET_LOW_HIGH: dflt = "target low-high"; break;
+ default:
+ log_err("Unknown default range value: %i", class->default_range);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultrange %s %s)", key, dflt);
+
+ }
+
+ if (class->constraints != NULL) {
+ rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (class->validatetrans != NULL) {
+ rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ rc = 0;
+
+exit:
+ free(arr.perms);
+ return rc;
+}
+
+static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ return 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(classorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+}
+
+static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+ char **types = NULL;
+ uint32_t num_types = 0;
+ struct role_datum *role = datum;
+ struct type_set *ts;
+
+ if (scope == SCOPE_REQ) {
+ // if a role/roleattr is in the REQ scope, then it could cause an
+ // optional block to fail, even if it is never used. However in CIL,
+ // symbols must be used in order to cause an optional block to fail. So
+ // for symbols in the REQ scope, add them to a roleattribute as a way
+ // to 'use' them in the optional without affecting the resulting policy.
+ cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
+ }
+
+ switch (role->flavor) {
+ case ROLE_ROLE:
+ if (scope == SCOPE_DECL) {
+ // Only declare certain roles if we are reading a base module.
+ // These roles are defined in the base module and sometimes in
+ // other non-base modules. If we generated the roles regardless of
+ // the policy type, it would result in duplicate declarations,
+ // which isn't allowed in CIL. Patches have been made to refpolicy
+ // to remove these duplicate role declarations, but we need to be
+ // backwards compatable and support older policies. Since we know
+ // these roles are always declared in base, only print them when we
+ // see them in the base module. If the declarations appear in a
+ // non-base module, ignore their declarations.
+ //
+ // Note that this is a hack, and if a policy author does not define
+ // one of these roles in base, the declaration will not appeaer in
+ // the resulting policy, likely resulting in a compilation error in
+ // CIL.
+ //
+ // To make things more complicated, the auditadm_r and secadm_r
+ // roles could actually be in either the base module or a non-base
+ // module, or both. So we can't rely on this same behavior. So for
+ // these roles, don't declare them here, even if they are in a base
+ // or non-base module. Instead we will just declare them in the
+ // base module elsewhere.
+ int is_base_role = (!strcmp(key, "user_r") ||
+ !strcmp(key, "staff_r") ||
+ !strcmp(key, "sysadm_r") ||
+ !strcmp(key, "system_r") ||
+ !strcmp(key, "unconfined_r"));
+ int is_builtin_role = (!strcmp(key, "auditadm_r") ||
+ !strcmp(key, "secadm_r"));
+ if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) ||
+ (!is_base_role && !is_builtin_role)) {
+ cil_println(indent, "(role %s)", key);
+ }
+ }
+
+ if (ebitmap_cardinality(&role->dominates) > 1) {
+ log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
+ }
+
+ ts = &role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < num_types; i++) {
+ if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+ cil_println(indent, "(roletype %s %s)", key, types[i]);
+ }
+ }
+
+ if (role->bounds > 0) {
+ cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
+ }
+ break;
+
+ case ROLE_ATTRIB:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(roleattribute %s)", key);
+ }
+
+ if (ebitmap_cardinality(&role->roles) > 0) {
+ cil_indent(indent);
+ cil_printf("(roleattributeset %s (", key);
+ ebitmap_for_each_bit(&role->roles, node, i) {
+ if (!ebitmap_get_bit(&role->roles, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_role_val_to_name[i]);
+ }
+ cil_printf("))\n");
+ }
+
+ ts = &role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+ if (rc != 0) {
+ goto exit;
+ }
+
+
+ for (i = 0; i < num_types; i++) {
+ if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+ cil_println(indent, "(roletype %s %s)", key, types[i]);
+ }
+ }
+
+ break;
+
+ default:
+ log_err("Unknown role type: %i", role->flavor);
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ names_destroy(&types, &num_types);
+
+ return rc;
+}
+
+static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct type_datum *type = datum;
+
+ if (scope == SCOPE_REQ) {
+ // if a type/typeattr is in the REQ scope, then it could cause an
+ // optional block to fail, even if it is never used. However in CIL,
+ // symbols must be used in order to cause an optional block to fail. So
+ // for symbols in the REQ scope, add them to a typeattribute as a way
+ // to 'use' them in the optional without affecting the resulting policy.
+ cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
+ }
+
+ rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ switch(type->flavor) {
+ case TYPE_TYPE:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(type %s)", key);
+ // object_r is implicit in checkmodule, but not with CIL,
+ // create it as part of base
+ cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
+ }
+
+ if (type->flags & TYPE_FLAGS_PERMISSIVE) {
+ cil_println(indent, "(typepermissive %s)", key);
+ }
+
+ if (type->bounds > 0) {
+ cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
+ }
+ break;
+ case TYPE_ATTRIB:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(typeattribute %s)", key);
+ }
+
+ if (ebitmap_cardinality(&type->types) > 0) {
+ cil_indent(indent);
+ cil_printf("(typeattributeset %s (", key);
+ ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
+ cil_printf("))\n");
+ }
+ break;
+ default:
+ log_err("Unknown flavor (%i) of type %s", type->flavor, key);
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct user_datum *user = datum;
+ struct ebitmap roles = user->roles.roles;
+ struct mls_semantic_level level = user->dfltlevel;
+ struct mls_semantic_range range = user->range;
+ struct ebitmap_node *node;
+ uint32_t i;
+ int sens_offset = 1;
+
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(user %s)", key);
+ // object_r is implicit in checkmodule, but not with CIL, create it
+ // as part of base
+ cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
+ }
+
+ ebitmap_for_each_bit(&roles, node, i) {
+ if (!ebitmap_get_bit(&roles, i)) {
+ continue;
+ }
+ cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
+ }
+
+ if (block->flags & AVRULE_OPTIONAL) {
+ // sensitivites in user statements in optionals do not have the
+ // standard -1 offest
+ sens_offset = 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(userlevel %s ", key);
+ if (pdb->mls) {
+ semantic_level_to_cil(pdb, sens_offset, &level);
+ } else {
+ cil_printf(DEFAULT_LEVEL);
+ }
+ cil_printf(")\n");
+
+ cil_indent(indent);
+ cil_printf("(userrange %s (", key);
+ if (pdb->mls) {
+ semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
+ cil_printf(" ");
+ semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
+ } else {
+ cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
+ }
+ cil_printf("))\n");
+
+
+ return 0;
+}
+
+static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct cond_bool_datum *boolean = datum;
+ const char *type;
+
+ if (scope == SCOPE_DECL) {
+ if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
+ type = "tunable";
+ } else {
+ type = "boolean";
+ }
+
+ cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
+ }
+
+ return 0;
+}
+
+static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct level_datum *level = datum;
+
+ if (scope == SCOPE_DECL) {
+ if (!level->isalias) {
+ cil_println(indent, "(sensitivity %s)", key);
+ } else {
+ cil_println(indent, "(sensitivityalias %s)", key);
+ cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
+ }
+ }
+
+ if (ebitmap_cardinality(&level->level->cat) > 0) {
+ cil_indent(indent);
+ cil_printf("(sensitivitycategory %s (", key);
+ ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
+ cil_printf("))\n");
+ }
+
+ return 0;
+}
+
+static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ return 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(sensitivityorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_sens_val_to_name[i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+}
+
+static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct cat_datum *cat = datum;
+
+ if (scope == SCOPE_REQ) {
+ return 0;
+ }
+
+ if (!cat->isalias) {
+ cil_println(indent, "(category %s)", key);
+ } else {
+ cil_println(indent, "(categoryalias %s)", key);
+ cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
+ }
+
+ return 0;
+}
+
+static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ rc = 0;
+ goto exit;
+ }
+
+ cil_indent(indent);
+ cil_printf("(categoryorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_cat_val_to_name[i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int polcaps_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ struct ebitmap *map;
+ struct ebitmap_node *node;
+ uint32_t i;
+ const char *name;
+
+ map = &pdb->policycaps;
+
+ ebitmap_for_each_bit(map, node, i) {
+ if (!ebitmap_get_bit(map, i)) {
+ continue;
+ }
+ name = sepol_polcap_getname(i);
+ if (name == NULL) {
+ log_err("Unknown policy capability id: %i", i);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(0, "(policycap %s)", name);
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int level_to_cil(struct policydb *pdb, struct mls_level *level)
+{
+ struct ebitmap *map = &level->cat;
+
+ cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
+
+ if (ebitmap_cardinality(map) > 0) {
+ cil_printf("(");
+ ebitmap_to_cil(pdb, map, SYM_CATS);
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ return 0;
+}
+
+static int context_to_cil(struct policydb *pdb, struct context_struct *con)
+{
+ cil_printf("(%s %s %s (",
+ pdb->p_user_val_to_name[con->user - 1],
+ pdb->p_role_val_to_name[con->role - 1],
+ pdb->p_type_val_to_name[con->type - 1]);
+
+ if (pdb->mls) {
+ level_to_cil(pdb, &con->range.level[0]);
+ cil_printf(" ");
+ level_to_cil(pdb, &con->range.level[1]);
+ } else {
+ cil_printf(DEFAULT_LEVEL);
+ cil_printf(" ");
+ cil_printf(DEFAULT_LEVEL);
+ }
+
+ cil_printf("))");
+
+ return 0;
+}
+
+static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
+{
+ int rc = -1;
+
+ struct ocontext *isid;
+
+ struct sid_item {
+ const char *sid_key;
+ struct sid_item *next;
+ };
+
+ struct sid_item *head = NULL;
+ struct sid_item *item = NULL;
+
+ for (isid = isids; isid != NULL; isid = isid->next) {
+ cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
+ cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
+ context_to_cil(pdb, &isid->context[0]);
+ cil_printf(")\n");
+
+ // get the sid names in the correct order (reverse from the isids
+ // ocontext) for sidorder statement
+ item = malloc(sizeof(*item));
+ if (item == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ item->sid_key = sid_to_string[isid->sid[0]];
+ item->next = head;
+ head = item;
+ }
+
+ if (head != NULL) {
+ cil_printf("(sidorder (");
+ for (item = head; item != NULL; item = item->next) {
+ cil_printf("%s ", item->sid_key);
+ }
+ cil_printf("))\n");
+ }
+
+ rc = 0;
+
+exit:
+ while(head) {
+ item = head;
+ head = item->next;
+ free(item);
+ }
+ return rc;
+}
+
+static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+ int rc = -1;
+
+ // initial sid names aren't actually stored in the pp files, need to a have
+ // a mapping, taken from the linux kernel
+ static const char *selinux_sid_to_string[] = {
+ "null",
+ "kernel",
+ "security",
+ "unlabeled",
+ "fs",
+ "file",
+ "file_labels",
+ "init",
+ "any_socket",
+ "port",
+ "netif",
+ "netmsg",
+ "node",
+ "igmp_packet",
+ "icmp_socket",
+ "tcp_socket",
+ "sysctl_modprobe",
+ "sysctl",
+ "sysctl_fs",
+ "sysctl_kernel",
+ "sysctl_net",
+ "sysctl_net_unix",
+ "sysctl_vm",
+ "sysctl_dev",
+ "kmod",
+ "policy",
+ "scmp_packet",
+ "devnull",
+ NULL
+ };
+
+ rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
+{
+ if (fss != NULL) {
+ log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
+ }
+
+ return 0;
+}
+
+static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
+{
+ int rc = -1;
+ struct ocontext *portcon;
+ const char *protocol;
+ uint16_t high;
+ uint16_t low;
+
+ for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
+
+ switch (portcon->u.port.protocol) {
+ case IPPROTO_TCP: protocol = "tcp"; break;
+ case IPPROTO_UDP: protocol = "udp"; break;
+ case IPPROTO_DCCP: protocol = "dccp"; break;
+ default:
+ log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
+ rc = -1;
+ goto exit;
+ }
+
+ low = portcon->u.port.low_port;
+ high = portcon->u.port.high_port;
+
+ if (low == high) {
+ cil_printf("(portcon %s %i ", protocol, low);
+ } else {
+ cil_printf("(portcon %s (%i %i) ", protocol, low, high);
+ }
+
+ context_to_cil(pdb, &portcon->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
+{
+ struct ocontext *netif;
+
+ for (netif = netifs; netif != NULL; netif = netif->next) {
+ cil_printf("(netifcon %s ", netif->u.name);
+ context_to_cil(pdb, &netif->context[0]);
+
+ cil_printf(" ");
+ context_to_cil(pdb, &netif->context[1]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+ int rc = -1;
+ struct ocontext *node;
+ char addr[INET_ADDRSTRLEN];
+ char mask[INET_ADDRSTRLEN];
+
+ for (node = nodes; node != NULL; node = node->next) {
+ if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon address is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon mask is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(nodecon %s %s ", addr, mask);
+
+ context_to_cil(pdb, &node->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+ int rc = -1;
+ struct ocontext *node;
+ char addr[INET6_ADDRSTRLEN];
+ char mask[INET6_ADDRSTRLEN];
+
+ for (node = nodes; node != NULL; node = node->next) {
+ if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon address is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon mask is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(nodecon %s %s ", addr, mask);
+
+ context_to_cil(pdb, &node->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
+{
+ int rc = -1;
+ struct ocontext *fsuse;
+ const char *behavior;
+
+
+ for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
+ switch (fsuse->v.behavior) {
+ case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
+ case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
+ case SECURITY_FS_USE_TASK: behavior = "task"; break;
+ default:
+ log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
+
+ context_to_cil(pdb, &fsuse->context[0]);
+
+ cil_printf(")\n");
+
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+ int rc = -1;
+
+ // initial sid names aren't actually stored in the pp files, need to a have
+ // a mapping, taken from the xen kernel
+ static const char *xen_sid_to_string[] = {
+ "null",
+ "xen",
+ "dom0",
+ "domio",
+ "domxen",
+ "unlabeled",
+ "security",
+ "ioport",
+ "iomem",
+ "irq",
+ "device",
+ NULL,
+ };
+
+ rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
+{
+ struct ocontext *pirq;
+
+ for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
+ cil_printf("(pirqcon %i ", pirq->u.pirq);
+ context_to_cil(pdb, &pirq->context[0]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
+{
+ struct ocontext *ioport;
+ uint32_t low;
+ uint32_t high;
+
+ for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
+ low = ioport->u.ioport.low_ioport;
+ high = ioport->u.ioport.high_ioport;
+
+ if (low == high) {
+ cil_printf("(ioportcon %i ", low);
+ } else {
+ cil_printf("(ioportcon (%i %i) ", low, high);
+ }
+
+ context_to_cil(pdb, &ioport->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
+{
+ struct ocontext *iomem;
+ uint64_t low;
+ uint64_t high;
+
+ for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
+ low = iomem->u.iomem.low_iomem;
+ high = iomem->u.iomem.high_iomem;
+
+ if (low == high) {
+ cil_printf("(iomemcon %#lX ", (unsigned long)low);
+ } else {
+ cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
+ }
+
+ context_to_cil(pdb, &iomem->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
+{
+ struct ocontext *pcid;
+
+ for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
+ cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
+ context_to_cil(pdb, &pcid->context[0]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontexts_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ int ocon;
+
+ static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
+ static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+ ocontext_selinux_isid_to_cil,
+ ocontext_selinux_fs_to_cil,
+ ocontext_selinux_port_to_cil,
+ ocontext_selinux_netif_to_cil,
+ ocontext_selinux_node_to_cil,
+ ocontext_selinux_fsuse_to_cil,
+ ocontext_selinux_node6_to_cil,
+ };
+ static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+ ocontext_xen_isid_to_cil,
+ ocontext_xen_pirq_to_cil,
+ ocontext_xen_ioport_to_cil,
+ ocontext_xen_iomem_to_cil,
+ ocontext_xen_pcidevice_to_cil,
+ NULL,
+ NULL,
+ };
+
+ switch (pdb->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ ocon_funcs = ocon_selinux_funcs;
+ break;
+ case SEPOL_TARGET_XEN:
+ ocon_funcs = ocon_xen_funcs;
+ break;
+ default:
+ log_err("Unknown target platform: %i", pdb->target_platform);
+ rc = -1;
+ goto exit;
+ }
+
+ for (ocon = 0; ocon < OCON_NUM; ocon++) {
+ if (ocon_funcs[ocon] != NULL) {
+ rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int genfscon_to_cil(struct policydb *pdb)
+{
+ struct genfs *genfs;
+ struct ocontext *ocon;
+
+ for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
+ for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
+ cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
+ context_to_cil(pdb, &ocon->context[0]);
+ cil_printf(")\n");
+ }
+ }
+
+ return 0;
+}
+
+static int level_string_to_cil(char *levelstr)
+{
+ int rc = -1;
+ char *sens = NULL;
+ char *cats = NULL;
+ int matched;
+ char *saveptr = NULL;
+ char *token = NULL;
+ char *ranged = NULL;
+
+ matched = tokenize(levelstr, ':', 2, &sens, &cats);
+ if (matched < 1 || matched > 2) {
+ log_err("Invalid level: %s", levelstr);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(%s", sens);
+
+ if (matched == 2) {
+ cil_printf("(");
+ token = strtok_r(cats, ",", &saveptr);
+ while (token != NULL) {
+ ranged = strchr(token, '.');
+ if (ranged == NULL) {
+ cil_printf("%s ", token);
+ } else {
+ *ranged = '\0';
+ cil_printf("(range %s %s) ", token, ranged + 1);
+ }
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ rc = 0;
+exit:
+ free(sens);
+ free(cats);
+ return rc;
+}
+
+static int level_range_string_to_cil(char *levelrangestr)
+{
+ char *ranged = NULL;
+ char *low;
+ char *high;
+
+ ranged = strchr(levelrangestr, '-');
+ if (ranged == NULL) {
+ low = high = levelrangestr;
+ } else {
+ *ranged = '\0';
+ low = levelrangestr;
+ high = ranged + 1;
+ }
+
+ level_string_to_cil(low);
+ cil_printf(" ");
+ level_string_to_cil(high);
+
+ return 0;
+}
+
+static int context_string_to_cil(char *contextstr)
+{
+ int rc = -1;
+ int matched;
+ char *user = NULL;
+ char *role = NULL;
+ char *type = NULL;
+ char *level = NULL;
+
+ matched = tokenize(contextstr, ':', 4, &user, &role, &type, &level);
+ if (matched < 3 || matched > 4) {
+ log_err("Invalid context: %s", contextstr);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(%s %s %s (", user, role, type);
+
+ if (matched == 3) {
+ cil_printf(DEFAULT_LEVEL);
+ cil_printf(" ");
+ cil_printf(DEFAULT_LEVEL);
+ } else {
+ level_range_string_to_cil(level);
+ }
+
+ cil_printf("))");
+
+ rc = 0;
+
+exit:
+ free(user);
+ free(role);
+ free(type);
+ free(level);
+
+ return rc;
+}
+
+static int seusers_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ char *seusers = sepol_module_package_get_seusers(mod_pkg);
+ size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
+ char *cur = seusers;
+ char *end = seusers + seusers_len;
+ char *line = NULL;
+ char *user = NULL;
+ char *seuser = NULL;
+ char *level = NULL;
+ char *tmp = NULL;
+ int matched;
+
+ if (seusers_len == 0) {
+ return 0;
+ }
+
+ while ((rc = get_line(&cur, end, &line)) > 0) {
+ tmp = line;
+ while (isspace(*tmp)) {
+ tmp++;
+ }
+
+ if (tmp[0] == '#' || tmp[0] == '\0') {
+ free(line);
+ line = NULL;
+ continue;
+ }
+
+ matched = tokenize(tmp, ':', 3, &user, &seuser, &level);
+
+ if (matched < 2 || matched > 3) {
+ log_err("Invalid seuser line: %s", line);
+ rc = -1;
+ goto exit;
+ }
+
+ if (!strcmp(user, "__default__")) {
+ cil_printf("(selinuxuserdefault %s (", seuser);
+ } else {
+ cil_printf("(selinuxuser %s %s (", user, seuser);
+ }
+
+ switch (matched) {
+ case 2:
+ cil_printf("systemlow systemlow");
+ break;
+ case 3:
+ level_range_string_to_cil(level);
+ break;
+ }
+
+ cil_printf("))\n");
+
+ free(user);
+ free(seuser);
+ free(level);
+ free(line);
+ user = seuser = level = NULL;
+ }
+
+ if (rc == -1) {
+ cil_printf("Failed to read seusers\n");
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ free(line);
+ free(user);
+ free(seuser);
+ free(level);
+
+ return rc;
+}
+
+static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+ size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
+
+ if (netcons_len > 0) {
+ log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
+ }
+
+ return 0;
+}
+
+static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ char *userx = sepol_module_package_get_user_extra(mod_pkg);
+ size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
+ char *cur = userx;
+ char *end = userx + userx_len;
+ char *line;
+ int matched;
+ char *user = NULL;
+ char *prefix = NULL;
+ int prefix_len = 0;
+ char *user_str = NULL;
+ char *prefix_str = NULL;
+ char *eol = NULL;
+ char *tmp = NULL;
+
+ if (userx_len == 0) {
+ return 0;
+ }
+
+ while ((rc = get_line(&cur, end, &line)) > 0) {
+ tmp = line;
+ while (isspace(*tmp)) {
+ tmp++;
+ }
+
+ if (tmp[0] == '#' || tmp[0] == '\0') {
+ free(line);
+ line = NULL;
+ continue;
+ }
+
+ matched = tokenize(tmp, ' ', 4, &user_str, &user, &prefix_str, &prefix);
+ if (matched != 4) {
+ rc = -1;
+ log_err("Invalid user extra line: %s", line);
+ goto exit;
+ }
+
+ prefix_len = strlen(prefix);
+ eol = prefix + prefix_len - 1;
+ if (*eol != ';' || strcmp(user_str, "user") || strcmp(prefix_str, "prefix")) {
+ rc = -1;
+ log_err("Invalid user extra line: %s", line);
+ goto exit;
+ }
+ *eol = '\0';
+
+ cil_println(0, "(userprefix %s %s)", user, prefix);
+ free(user);
+ free(prefix);
+ free(line);
+ free(user_str);
+ free(prefix_str);
+ user = prefix = line = user_str = prefix_str = NULL;
+ }
+
+ if (rc == -1) {
+ cil_printf("Failed to read user_extra\n");
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ free(line);
+ free(user);
+ free(prefix);
+
+ return rc;
+}
+
+static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ char *fc = sepol_module_package_get_file_contexts(mod_pkg);
+ size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
+ char *cur = fc;
+ char *end = fc + fc_len;
+ char *line = NULL;
+ int matched;
+ char *regex = NULL;
+ char *mode = NULL;
+ char *context = NULL;
+ const char *cilmode;
+ char *tmp = NULL;
+
+ if (fc_len == 0) {
+ return 0;
+ }
+
+ while ((rc = get_line(&cur, end, &line)) > 0) {
+ tmp = line;
+ while (isspace(*tmp)) {
+ tmp++;
+ }
+
+ if (tmp[0] == '#' || tmp[0] == '\0') {
+ free(line);
+ line = NULL;
+ continue;
+ }
+
+ matched = tokenize(tmp, ' ', 3, ®ex, &mode, &context);
+ if (matched < 2 || matched > 3) {
+ rc = -1;
+ log_err("Invalid file context line: %s", line);
+ goto exit;
+ }
+
+ if (matched == 2) {
+ context = mode;
+ mode = NULL;
+ }
+
+ if (mode == NULL) {
+ cilmode = "any";
+ } else if (!strcmp(mode, "--")) {
+ cilmode = "file";
+ } else if (!strcmp(mode, "-d")) {
+ cilmode = "dir";
+ } else if (!strcmp(mode, "-c")) {
+ cilmode = "char";
+ } else if (!strcmp(mode, "-b")) {
+ cilmode = "block";
+ } else if (!strcmp(mode, "-s")) {
+ cilmode = "socket";
+ } else if (!strcmp(mode, "-p")) {
+ cilmode = "pipe";
+ } else if (!strcmp(mode, "-l")) {
+ cilmode = "symlink";
+ } else {
+ rc = -1;
+ log_err("Invalid mode in file context line: %s", line);
+ goto exit;
+ }
+
+ cil_printf("(filecon \"%s\" %s ", regex, cilmode);
+
+ if (!strcmp(context, "<<none>>")) {
+ cil_printf("()");
+ } else {
+ context_string_to_cil(context);
+ }
+
+ cil_printf(")\n");
+
+ free(regex);
+ free(mode);
+ free(context);
+ free(line);
+ regex = mode = context = line = NULL;
+ }
+
+ if (rc == -1) {
+ cil_printf("Failed to read file_contexts_to_cil\n");
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ free(line);
+ free(regex);
+ free(mode);
+ free(context);
+
+ return rc;
+}
+
+
+static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
+ NULL, // commons, only stored in the global symtab, handled elsewhere
+ class_to_cil,
+ role_to_cil,
+ type_to_cil,
+ user_to_cil,
+ boolean_to_cil,
+ sens_to_cil,
+ cat_to_cil
+};
+
+static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
+{
+ struct type_datum *alias_datum;
+ char *alias_name;
+ struct list_node *curr;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+ struct list *alias_list = typealias_lists[decl->decl_id];
+ int rc = -1;
+
+ if (alias_list == NULL) {
+ return 0;
+ }
+
+ for (curr = alias_list->head; curr != NULL; curr = curr->next) {
+ alias_name = curr->data;
+ alias_datum = hashtab_search(pdb->p_types.table, alias_name);
+ if (alias_datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(indent, "(typealias %s)", alias_name);
+ cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct ebitmap map;
+ struct ebitmap_node *node;
+ unsigned int i;
+ char * key;
+ struct scope_datum *scope;
+ int sym;
+ void *datum;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+
+ for (sym = 0; sym < SYM_NUM; sym++) {
+ if (func_to_cil[sym] == NULL) {
+ continue;
+ }
+
+ map = decl->declared.scope[sym];
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+ key = pdb->sym_val_to_name[sym][i];
+ datum = hashtab_search(pdb->symtab[sym].table, key);
+ if (datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ scope = hashtab_search(pdb->scope[sym].table, key);
+ if (scope == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_CATS) {
+ rc = cat_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_LEVELS) {
+ rc = sens_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_CLASSES) {
+ rc = class_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct ebitmap map;
+ struct ebitmap_node *node;
+ unsigned int i;
+ unsigned int j;
+ char * key;
+ int sym;
+ void *datum;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+ struct scope_datum *scope_datum;
+
+ for (sym = 0; sym < SYM_NUM; sym++) {
+ if (func_to_cil[sym] == NULL) {
+ continue;
+ }
+
+ map = decl->required.scope[sym];
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+ key = pdb->sym_val_to_name[sym][i];
+
+ scope_datum = hashtab_search(pdb->scope[sym].table, key);
+ for (j = 0; j < scope_datum->decl_ids_len; j++) {
+ if (scope_datum->decl_ids[j] == decl->decl_id) {
+ break;
+ }
+ }
+ if (j >= scope_datum->decl_ids_len) {
+ // Symbols required in the global scope are also in the
+ // required scope ebitmap of all avrule decls (i.e. required
+ // in all optionals). So we need to look at the scopes of each
+ // symbol in this avrule_decl to determine if it actually is
+ // required in this decl, or if it's just required in the
+ // global scope. If we got here, then this symbol is not
+ // actually required in this scope, so skip it.
+ continue;
+ }
+
+ datum = hashtab_search(pdb->symtab[sym].table, key);
+ if (datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
+{
+ int rc = -1;
+ struct map_args *args = arg;
+
+ rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct map_args args;
+ args.pdb = pdb;
+ args.block = block;
+ args.decl_stack = decl_stack;
+ args.indent = indent;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+
+ for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
+ rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
+{
+ // returns 1 if sup is a superset of sub, returns 0 otherwise
+
+ int rc = 0;
+
+ uint32_t i;
+ struct ebitmap sup_map;
+ struct ebitmap sub_map;
+ struct ebitmap res;
+
+ ebitmap_init(&res);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ sup_map = sup->scope[i];
+ sub_map = sub->scope[i];
+
+ ebitmap_and(&res, &sup_map, &sub_map);
+ if (!ebitmap_cmp(&res, &sub_map)) {
+ goto exit;
+ }
+ ebitmap_destroy(&res);
+ }
+
+ if (sup->class_perms_len < sub->class_perms_len) {
+ goto exit;
+ }
+
+ for (i = 0; i < sub->class_perms_len; i++) {
+ sup_map = sup->class_perms_map[i];
+ sub_map = sub->class_perms_map[i];
+
+ ebitmap_and(&res, &sup_map, &sub_map);
+ if (!ebitmap_cmp(&res, &sub_map)) {
+ goto exit;
+ }
+ ebitmap_destroy(&res);
+ }
+
+ rc = 1;
+
+exit:
+
+ ebitmap_destroy(&res);
+ return rc;
+}
+
+static int block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack, int indent)
+{
+ int rc = -1;
+ struct avrule_decl *decl;
+ struct list *attr_list;
+
+ decl = block->branch_list;
+
+ rc = list_init(&attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = typealiases_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = declared_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = required_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = additive_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = cond_list_to_cil(indent, pdb, decl->cond_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = cil_print_attr_list(indent, pdb, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+exit:
+ attr_list_destroy(&attr_list);
+ return rc;
+}
+
+static int module_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack, int *indent)
+{
+ int rc = 0;
+ struct avrule_decl *decl;
+ struct avrule_decl *decl_tmp;
+
+ decl = block->branch_list;
+ if (decl == NULL) {
+ goto exit;
+ }
+
+ if (decl->next != NULL) {
+ log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
+ }
+
+ if (block->flags & AVRULE_OPTIONAL) {
+ while (stack->pos > 0) {
+ decl_tmp = stack_peek(stack);
+ if (is_scope_superset(&decl->required, &decl_tmp->required)) {
+ break;
+ }
+
+ stack_pop(stack);
+ (*indent)--;
+ cil_println(*indent, ")");
+ }
+
+ cil_println(*indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
+ (*indent)++;
+ }
+
+ stack_push(stack, decl);
+
+ rc = block_to_cil(pdb, block, stack, *indent);
+ if (rc != 0) {
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+static int global_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack)
+{
+ int rc = 0;
+ struct avrule_decl *decl;
+
+ decl = block->branch_list;
+ if (decl == NULL) {
+ goto exit;
+ }
+
+ if (decl->next != NULL) {
+ log_err("Warning: 'else' not allowed in global block. Dropping from output.");
+ }
+
+ stack_push(stack, decl);
+
+ // type aliases and commons are only stored in the global symtab.
+ // However, to get scoping correct, we assume they are in the
+ // global block
+ rc = hashtab_map(pdb->p_commons.table, common_to_cil, NULL);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = block_to_cil(pdb, block, stack, 0);
+ if (rc != 0) {
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+static int blocks_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ struct avrule_block *block;
+ int indent = 0;
+ struct stack *stack;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ block = pdb->global;
+ rc = global_block_to_cil(pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (block = block->next; block != NULL; block = block->next) {
+ rc = module_block_to_cil(pdb, block, stack, &indent);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ while (indent > 0) {
+ indent--;
+ cil_println(indent, ")");
+ }
+
+exit:
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+static int linked_block_to_cil(struct policydb *pdb, struct avrule_block *block, struct stack *stack)
+{
+ int rc = 0;
+ struct avrule_decl *decl;
+
+ decl = block->branch_list;
+ if (decl == NULL) {
+ goto exit;
+ }
+
+ if (!decl->enabled) {
+ if (decl->next != NULL) {
+ decl = decl->next;
+ } else {
+ goto exit;
+ }
+ }
+
+ stack_push(stack, decl);
+
+ rc = block_to_cil(pdb, block, stack, 0);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ stack_pop(stack);
+
+exit:
+ return rc;
+}
+
+static int linked_blocks_to_cil(struct policydb *pdb)
+{
+ // Convert base module that has been linked to CIL
+ // Since it is linked, all optional blocks have been resolved
+ int rc = -1;
+ struct avrule_block *block;
+ struct stack *stack;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ block = pdb->global;
+ rc = global_block_to_cil(pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (block = block->next; block != NULL; block = block->next) {
+ rc = linked_block_to_cil(pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+static int handle_unknown_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ const char *hu;
+
+ switch (pdb->handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ hu = "deny";
+ break;
+ case SEPOL_REJECT_UNKNOWN:
+ hu = "reject";
+ break;
+ case SEPOL_ALLOW_UNKNOWN:
+ hu = "allow";
+ break;
+ default:
+ log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(0, "(handleunknown %s)", hu);
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int generate_mls(struct policydb *pdb)
+{
+ const char *mls_str = pdb->mls ? "true" : "false";
+ cil_println(0, "(mls %s)", mls_str);
+
+ return 0;
+}
+
+static int generate_default_level(void)
+{
+ cil_println(0, "(sensitivity s0)");
+ cil_println(0, "(sensitivityorder (s0))");
+ cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
+
+ return 0;
+}
+
+static int generate_default_object(void)
+{
+ cil_println(0, "(role " DEFAULT_OBJECT ")");
+
+ return 0;
+}
+
+static int generate_builtin_roles(void)
+{
+ // due to inconsistentencies between policies and CIL not allowing
+ // duplicate roles, some roles are always created, regardless of if they
+ // are declared in modules or not
+ cil_println(0, "(role auditadm_r)");
+ cil_println(0, "(role secadm_r)");
+
+ return 0;
+}
+
+static int generate_gen_require_attribute(void)
+{
+ cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
+ cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
+
+ return 0;
+}
+
+static int fix_module_name(struct policydb *pdb)
+{
+ char *letter;
+ int rc = -1;
+
+ // The base module doesn't have its name set, but we use that for some
+ // autogenerated names, like optionals and attributes, to prevent naming
+ // collisions. However, they sometimes need to be fixed up.
+
+ // the base module isn't given a name, so just call it "base"
+ if (pdb->policy_type == POLICY_BASE) {
+ pdb->name = strdup("base");
+ if (pdb->name == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+
+ // CIL is more restrictive in module names than checkmodule. Convert bad
+ // characters to underscores
+ for (letter = pdb->name; *letter != '\0'; letter++) {
+ if (isalnum(*letter)) {
+ continue;
+ }
+
+ *letter = '_';
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+int sepol_module_policydb_to_cil(FILE *fp, struct policydb *pdb, int linked)
+{
+ int rc = -1;
+
+ out_file = fp;
+
+ if (pdb == NULL) {
+ rc = 0;
+ goto exit;
+ }
+
+ if (pdb->policy_type != SEPOL_POLICY_BASE &&
+ pdb->policy_type != SEPOL_POLICY_MOD) {
+ log_err("Policy pakcage is not a base or module");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = fix_module_name(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (pdb->policy_type == SEPOL_POLICY_BASE && !pdb->mls) {
+ // If this is a base non-mls policy, we need to define a default level
+ // range that can be used for contexts by other non-mls modules, since
+ // CIL requires that all contexts have a range, even if they are
+ // ignored as in non-mls policies
+ rc = generate_default_level();
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (pdb->policy_type == SEPOL_POLICY_BASE) {
+ // object_r is implicit in checkmodule, but not with CIL, create it
+ // as part of base
+ rc = generate_default_object();
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = generate_builtin_roles();
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // default attribute to be used to mimic gen_require in CIL
+ rc = generate_gen_require_attribute();
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // handle_unknown is used from only the base module
+ rc = handle_unknown_to_cil(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // mls is used from only the base module
+ rc = generate_mls(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ rc = role_list_create(pdb->p_roles.table);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = typealias_list_create(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = polcaps_to_cil(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = ocontexts_to_cil(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = genfscon_to_cil(pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // now print everything that is scoped
+ if (linked) {
+ rc = linked_blocks_to_cil(pdb);
+ } else {
+ rc = blocks_to_cil(pdb);
+ }
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ role_list_destroy();
+ typealias_list_destroy();
+
+ return rc;
+}
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ struct sepol_policydb *pdb;
+
+ out_file = fp;
+
+ pdb = sepol_module_package_get_policy(mod_pkg);
+ if (pdb == NULL) {
+ log_err("Failed to get policydb");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = sepol_module_policydb_to_cil(fp, &pdb->p, 0);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = seusers_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = netfilter_contexts_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = user_extra_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = file_contexts_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
+{
+ int rc = -1;
+ char *d = NULL;
+ size_t d_len = 0;
+ size_t read_len = 0;
+ size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
+
+ d = malloc(max_len);
+ if (d == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
+ d_len += read_len;
+ if (d_len == max_len) {
+ max_len *= 2;
+ d = realloc(d, max_len);
+ if (d == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+ }
+
+ if (ferror(fp) != 0) {
+ log_err("Failed to read pp file");
+ rc = -1;
+ goto exit;
+ }
+
+ *data = d;
+ *data_len = d_len;
+
+ return 0;
+
+exit:
+ free(d);
+ return rc;
+}
+
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
+{
+ int rc = -1;
+ FILE *f = NULL;
+ struct sepol_policy_file *pf = NULL;
+ struct sepol_module_package *pkg = NULL;
+ char *data = NULL;
+ size_t data_len;
+ int fd;
+ struct stat sb;
+
+ rc = sepol_policy_file_create(&pf);
+ if (rc != 0) {
+ log_err("Failed to create policy file");
+ goto exit;
+ }
+
+ fd = fileno(fp);
+ if (fstat(fd, &sb) == -1) {
+ rc = -1;
+ goto exit;
+ }
+
+ if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
+ // libsepol fails when trying to read a policy package from a pipe or a
+ // socket due its use of lseek. In this case, read the data into a
+ // buffer and provide that to libsepol
+ rc = fp_to_buffer(fp, &data, &data_len);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ sepol_policy_file_set_mem(pf, data, data_len);
+ } else {
+ sepol_policy_file_set_fp(pf, fp);
+ }
+
+ rc = sepol_module_package_create(&pkg);
+ if (rc != 0) {
+ log_err("Failed to create module package");
+ goto exit;
+ }
+
+ rc = sepol_module_package_read(pkg, pf, 0);
+ if (rc != 0) {
+ log_err("Failed to read policy package");
+ goto exit;
+ }
+
+ *mod_pkg = pkg;
+
+exit:
+ free(data);
+
+ sepol_policy_file_free(pf);
+ if (f != NULL) {
+ fclose(f);
+ }
+
+ if (rc != 0) {
+ sepol_module_package_free(pkg);
+ }
+
+ return rc;
+}
diff --git a/libsepol/src/node_internal.h b/libsepol/src/node_internal.h
new file mode 100644
index 0000000..802cda9
--- /dev/null
+++ b/libsepol/src/node_internal.h
@@ -0,0 +1,26 @@
+#ifndef _SEPOL_NODE_INTERNAL_H_
+#define _SEPOL_NODE_INTERNAL_H_
+
+#include <sepol/node_record.h>
+#include <sepol/nodes.h>
+#include "dso.h"
+
+hidden_proto(sepol_node_create)
+ hidden_proto(sepol_node_key_free)
+ hidden_proto(sepol_node_free)
+ hidden_proto(sepol_node_get_con)
+ hidden_proto(sepol_node_get_addr)
+ hidden_proto(sepol_node_get_addr_bytes)
+ hidden_proto(sepol_node_get_mask)
+ hidden_proto(sepol_node_get_mask_bytes)
+ hidden_proto(sepol_node_get_proto)
+ hidden_proto(sepol_node_get_proto_str)
+ hidden_proto(sepol_node_key_create)
+ hidden_proto(sepol_node_key_unpack)
+ hidden_proto(sepol_node_set_con)
+ hidden_proto(sepol_node_set_addr)
+ hidden_proto(sepol_node_set_addr_bytes)
+ hidden_proto(sepol_node_set_mask)
+ hidden_proto(sepol_node_set_mask_bytes)
+ hidden_proto(sepol_node_set_proto)
+#endif
diff --git a/libsepol/src/node_record.c b/libsepol/src/node_record.c
new file mode 100644
index 0000000..21043b6
--- /dev/null
+++ b/libsepol/src/node_record.c
@@ -0,0 +1,675 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "node_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_node {
+
+ /* Network address and mask */
+ char *addr;
+ size_t addr_sz;
+
+ char *mask;
+ size_t mask_sz;
+
+ /* Protocol */
+ int proto;
+
+ /* Context */
+ sepol_context_t *con;
+};
+
+struct sepol_node_key {
+
+ /* Network address and mask */
+ char *addr;
+ size_t addr_sz;
+
+ char *mask;
+ size_t mask_sz;
+
+ /* Protocol */
+ int proto;
+};
+
+/* Converts a string represtation (addr_str)
+ * to a numeric representation (addr_bytes) */
+
+static int node_parse_addr(sepol_handle_t * handle,
+ const char *addr_str, int proto, char *addr_bytes)
+{
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ struct in_addr in_addr;
+
+ if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) {
+ ERR(handle, "could not parse IPv4 address "
+ "%s: %s", addr_str, strerror(errno));
+ return STATUS_ERR;
+ }
+
+ memcpy(addr_bytes, &in_addr.s_addr, 4);
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ struct in6_addr in_addr;
+
+ if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) {
+ ERR(handle, "could not parse IPv6 address "
+ "%s: %s", addr_str, strerror(errno));
+ return STATUS_ERR;
+ }
+
+#ifdef __APPLE__
+ memcpy(addr_bytes, in_addr.s6_addr, 16);
+#else
+ memcpy(addr_bytes, in_addr.s6_addr32, 16);
+#endif
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u, could not "
+ "parse address", proto);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large buffer (addr, addr_sz)
+ * according the the protocol */
+
+static int node_alloc_addr(sepol_handle_t * handle,
+ int proto, char **addr, size_t * addr_sz)
+{
+
+ char *tmp_addr = NULL;
+ size_t tmp_addr_sz;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ tmp_addr_sz = 4;
+ tmp_addr = malloc(4);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ tmp_addr_sz = 16;
+ tmp_addr = malloc(16);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *addr = tmp_addr;
+ *addr_sz = tmp_addr_sz;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not allocate address of protocol %s",
+ sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Converts a numeric representation (addr_bytes)
+ * to a string representation (addr_str), according to
+ * the protocol */
+
+static int node_expand_addr(sepol_handle_t * handle,
+ char *addr_bytes, int proto, char *addr_str)
+{
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ struct in_addr addr;
+ memset(&addr, 0, sizeof(struct in_addr));
+ memcpy(&addr.s_addr, addr_bytes, 4);
+
+ if (inet_ntop(AF_INET, &addr, addr_str,
+ INET_ADDRSTRLEN) == NULL) {
+
+ ERR(handle,
+ "could not expand IPv4 address to string: %s",
+ strerror(errno));
+ return STATUS_ERR;
+ }
+ break;
+ }
+
+ case SEPOL_PROTO_IP6:
+ {
+ struct in6_addr addr;
+ memset(&addr, 0, sizeof(struct in6_addr));
+#ifdef __APPLE__
+ memcpy(&addr.s6_addr[0], addr_bytes, 16);
+#else
+ memcpy(&addr.s6_addr32[0], addr_bytes, 16);
+#endif
+ if (inet_ntop(AF_INET6, &addr, addr_str,
+ INET6_ADDRSTRLEN) == NULL) {
+
+ ERR(handle,
+ "could not expand IPv6 address to string: %s",
+ strerror(errno));
+ return STATUS_ERR;
+ }
+ break;
+ }
+
+ default:
+ ERR(handle, "unsupported protocol %u, could not"
+ " expand address to string", proto);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large address string (addr)
+ * according to the protocol */
+
+static int node_alloc_addr_string(sepol_handle_t * handle,
+ int proto, char **addr)
+{
+
+ char *tmp_addr = NULL;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ tmp_addr = malloc(INET_ADDRSTRLEN);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ tmp_addr = malloc(INET6_ADDRSTRLEN);
+ if (!tmp_addr)
+ goto omem;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *addr = tmp_addr;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not allocate string buffer for "
+ "address of protocol %s", sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Key */
+int sepol_node_key_create(sepol_handle_t * handle,
+ const char *addr,
+ const char *mask,
+ int proto, sepol_node_key_t ** key_ptr)
+{
+
+ sepol_node_key_t *tmp_key =
+ (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+ if (!tmp_key)
+ goto omem;
+
+ if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) <
+ 0)
+ goto err;
+ if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0)
+ goto err;
+
+ if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) <
+ 0)
+ goto err;
+ if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0)
+ goto err;
+
+ tmp_key->proto = proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ sepol_node_key_free(tmp_key);
+ ERR(handle, "could not create node key for (%s, %s, %s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_key_create)
+
+void sepol_node_key_unpack(const sepol_node_key_t * key,
+ const char **addr, const char **mask, int *proto)
+{
+
+ *addr = key->addr;
+ *mask = key->mask;
+ *proto = key->proto;
+}
+
+hidden_def(sepol_node_key_unpack)
+
+int sepol_node_key_extract(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ sepol_node_key_t ** key_ptr)
+{
+
+ sepol_node_key_t *tmp_key =
+ (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
+ if (!tmp_key)
+ goto omem;
+
+ tmp_key->addr = malloc(node->addr_sz);
+ tmp_key->mask = malloc(node->mask_sz);
+
+ if (!tmp_key->addr || !tmp_key->mask)
+ goto omem;
+
+ memcpy(tmp_key->addr, node->addr, node->addr_sz);
+ memcpy(tmp_key->mask, node->mask, node->mask_sz);
+ tmp_key->addr_sz = node->addr_sz;
+ tmp_key->mask_sz = node->mask_sz;
+ tmp_key->proto = node->proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+
+ omem:
+ sepol_node_key_free(tmp_key);
+ ERR(handle, "out of memory, could not extract node key");
+ return STATUS_ERR;
+}
+
+void sepol_node_key_free(sepol_node_key_t * key)
+{
+
+ if (!key)
+ return;
+
+ free(key->addr);
+ free(key->mask);
+ free(key);
+}
+
+hidden_def(sepol_node_key_free)
+
+int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key)
+{
+
+ int rc1, rc2;
+
+ if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz))
+ return -1;
+
+ else if ((node->addr_sz > key->addr_sz) ||
+ (node->mask_sz > key->mask_sz))
+ return 1;
+
+ rc1 = memcmp(node->addr, key->addr, node->addr_sz);
+ rc2 = memcmp(node->mask, key->mask, node->mask_sz);
+
+ return (rc2 != 0) ? rc2 : rc1;
+}
+
+int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2)
+{
+
+ int rc1, rc2;
+
+ if ((node->addr_sz < node2->addr_sz) ||
+ (node->mask_sz < node2->mask_sz))
+ return -1;
+
+ else if ((node->addr_sz > node2->addr_sz) ||
+ (node->mask_sz > node2->mask_sz))
+ return 1;
+
+ rc1 = memcmp(node->addr, node2->addr, node->addr_sz);
+ rc2 = memcmp(node->mask, node2->mask, node->mask_sz);
+
+ return (rc2 != 0) ? rc2 : rc1;
+}
+
+/* Addr */
+int sepol_node_get_addr(sepol_handle_t * handle,
+ const sepol_node_t * node, char **addr)
+{
+
+ char *tmp_addr = NULL;
+
+ if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0)
+ goto err;
+
+ if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0)
+ goto err;
+
+ *addr = tmp_addr;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not get node address");
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_addr)
+
+int sepol_node_get_addr_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **buffer, size_t * bsize)
+{
+
+ char *tmp_buf = malloc(node->addr_sz);
+ if (!tmp_buf) {
+ ERR(handle, "out of memory, could not get address bytes");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_buf, node->addr, node->addr_sz);
+ *buffer = tmp_buf;
+ *bsize = node->addr_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_addr_bytes)
+
+int sepol_node_set_addr(sepol_handle_t * handle,
+ sepol_node_t * node, int proto, const char *addr)
+{
+
+ char *tmp_addr = NULL;
+ size_t tmp_addr_sz;
+
+ if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0)
+ goto err;
+
+ if (node_parse_addr(handle, addr, proto, tmp_addr) < 0)
+ goto err;
+
+ free(node->addr);
+ node->addr = tmp_addr;
+ node->addr_sz = tmp_addr_sz;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_addr);
+ ERR(handle, "could not set node address to %s", addr);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_addr)
+
+int sepol_node_set_addr_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *addr, size_t addr_sz)
+{
+
+ char *tmp_addr = malloc(addr_sz);
+ if (!tmp_addr) {
+ ERR(handle, "out of memory, could not " "set node address");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_addr, addr, addr_sz);
+ free(node->addr);
+ node->addr = tmp_addr;
+ node->addr_sz = addr_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_addr_bytes)
+
+/* Mask */
+int sepol_node_get_mask(sepol_handle_t * handle,
+ const sepol_node_t * node, char **mask)
+{
+
+ char *tmp_mask = NULL;
+
+ if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0)
+ goto err;
+
+ if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0)
+ goto err;
+
+ *mask = tmp_mask;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_mask);
+ ERR(handle, "could not get node netmask");
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_get_mask)
+
+int sepol_node_get_mask_bytes(sepol_handle_t * handle,
+ const sepol_node_t * node,
+ char **buffer, size_t * bsize)
+{
+
+ char *tmp_buf = malloc(node->mask_sz);
+ if (!tmp_buf) {
+ ERR(handle, "out of memory, could not get netmask bytes");
+ return STATUS_ERR;
+ }
+
+ memcpy(tmp_buf, node->mask, node->mask_sz);
+ *buffer = tmp_buf;
+ *bsize = node->mask_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_get_mask_bytes)
+
+int sepol_node_set_mask(sepol_handle_t * handle,
+ sepol_node_t * node, int proto, const char *mask)
+{
+
+ char *tmp_mask = NULL;
+ size_t tmp_mask_sz;
+
+ if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0)
+ goto err;
+
+ if (node_parse_addr(handle, mask, proto, tmp_mask) < 0)
+ goto err;
+
+ free(node->mask);
+ node->mask = tmp_mask;
+ node->mask_sz = tmp_mask_sz;
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_mask);
+ ERR(handle, "could not set node netmask to %s", mask);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_node_set_mask)
+
+int sepol_node_set_mask_bytes(sepol_handle_t * handle,
+ sepol_node_t * node,
+ const char *mask, size_t mask_sz)
+{
+
+ char *tmp_mask = malloc(mask_sz);
+ if (!tmp_mask) {
+ ERR(handle, "out of memory, could not " "set node netmask");
+ return STATUS_ERR;
+ }
+ memcpy(tmp_mask, mask, mask_sz);
+ free(node->mask);
+ node->mask = tmp_mask;
+ node->mask_sz = mask_sz;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_mask_bytes)
+
+/* Protocol */
+int sepol_node_get_proto(const sepol_node_t * node)
+{
+
+ return node->proto;
+}
+
+hidden_def(sepol_node_get_proto)
+
+void sepol_node_set_proto(sepol_node_t * node, int proto)
+{
+
+ node->proto = proto;
+}
+
+hidden_def(sepol_node_set_proto)
+
+const char *sepol_node_get_proto_str(int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_IP4:
+ return "ipv4";
+ case SEPOL_PROTO_IP6:
+ return "ipv6";
+ default:
+ return "???";
+ }
+}
+
+hidden_def(sepol_node_get_proto_str)
+
+/* Create */
+int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node)
+{
+
+ sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t));
+
+ if (!tmp_node) {
+ ERR(handle, "out of memory, could not create " "node record");
+ return STATUS_ERR;
+ }
+
+ tmp_node->addr = NULL;
+ tmp_node->addr_sz = 0;
+ tmp_node->mask = NULL;
+ tmp_node->mask_sz = 0;
+ tmp_node->proto = SEPOL_PROTO_IP4;
+ tmp_node->con = NULL;
+ *node = tmp_node;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_create)
+
+/* Deep copy clone */
+int sepol_node_clone(sepol_handle_t * handle,
+ const sepol_node_t * node, sepol_node_t ** node_ptr)
+{
+
+ sepol_node_t *new_node = NULL;
+ if (sepol_node_create(handle, &new_node) < 0)
+ goto err;
+
+ /* Copy address, mask, protocol */
+ new_node->addr = malloc(node->addr_sz);
+ new_node->mask = malloc(node->mask_sz);
+ if (!new_node->addr || !new_node->mask)
+ goto omem;
+
+ memcpy(new_node->addr, node->addr, node->addr_sz);
+ memcpy(new_node->mask, node->mask, node->mask_sz);
+ new_node->addr_sz = node->addr_sz;
+ new_node->mask_sz = node->mask_sz;
+ new_node->proto = node->proto;
+
+ /* Copy context */
+ if (node->con &&
+ (sepol_context_clone(handle, node->con, &new_node->con) < 0))
+ goto err;
+
+ *node_ptr = new_node;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not clone node record");
+ sepol_node_free(new_node);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_node_free(sepol_node_t * node)
+{
+
+ if (!node)
+ return;
+
+ sepol_context_free(node->con);
+ free(node->addr);
+ free(node->mask);
+ free(node);
+}
+
+hidden_def(sepol_node_free)
+
+/* Context */
+sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
+{
+
+ return node->con;
+}
+
+hidden_def(sepol_node_get_con)
+
+int sepol_node_set_con(sepol_handle_t * handle,
+ sepol_node_t * node, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set node context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(node->con);
+ node->con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_node_set_con)
diff --git a/libsepol/src/nodes.c b/libsepol/src/nodes.c
new file mode 100644
index 0000000..50cf21d
--- /dev/null
+++ b/libsepol/src/nodes.c
@@ -0,0 +1,399 @@
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "node_internal.h"
+
+/* Create a low level node structure from
+ * a high level representation */
+static int node_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** node, const sepol_node_t * data)
+{
+
+ ocontext_t *tmp_node = NULL;
+ context_struct_t *tmp_con = NULL;
+ char *addr_buf = NULL, *mask_buf = NULL;
+
+ tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_node)
+ goto omem;
+
+ size_t addr_bsize, mask_bsize;
+
+ /* Address and netmask */
+ if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
+ goto err;
+ if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
+ goto err;
+
+ int proto = sepol_node_get_proto(data);
+
+ switch (proto) {
+ case SEPOL_PROTO_IP4:
+ memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
+ memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
+ break;
+ case SEPOL_PROTO_IP6:
+ memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
+ memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
+ break;
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+ free(addr_buf);
+ free(mask_buf);
+ addr_buf = NULL;
+ mask_buf = NULL;
+
+ /* Context */
+ if (context_from_record(handle, policydb, &tmp_con,
+ sepol_node_get_con(data)) < 0)
+ goto err;
+ context_cpy(&tmp_node->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *node = tmp_node;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_node != NULL) {
+ context_destroy(&tmp_node->context[0]);
+ free(tmp_node);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ free(addr_buf);
+ free(mask_buf);
+ ERR(handle, "could not create node structure");
+ return STATUS_ERR;
+}
+
+static int node_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * node, int proto, sepol_node_t ** record)
+{
+
+ context_struct_t *con = &node->context[0];
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_node_t *tmp_record = NULL;
+
+ if (sepol_node_create(handle, &tmp_record) < 0)
+ goto err;
+
+ sepol_node_set_proto(tmp_record, proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ if (sepol_node_set_addr_bytes(handle, tmp_record,
+ (const char *)&node->u.node.addr,
+ 4) < 0)
+ goto err;
+
+ if (sepol_node_set_mask_bytes(handle, tmp_record,
+ (const char *)&node->u.node.mask,
+ 4) < 0)
+ goto err;
+ break;
+
+ case SEPOL_PROTO_IP6:
+ if (sepol_node_set_addr_bytes(handle, tmp_record,
+ (const char *)&node->u.node6.addr,
+ 16) < 0)
+ goto err;
+
+ if (sepol_node_set_mask_bytes(handle, tmp_record,
+ (const char *)&node->u.node6.mask,
+ 16) < 0)
+ goto err;
+ break;
+
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+ goto err;
+
+ if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
+ goto err;
+
+ sepol_context_free(tmp_con);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert node to record");
+ sepol_context_free(tmp_con);
+ sepol_node_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Return the number of nodes */
+extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ return STATUS_SUCCESS;
+}
+
+/* Check if a node exists */
+int sepol_node_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_node_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int proto;
+ const char *addr, *mask;
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = &c->u.node.addr;
+ unsigned int *mask2 = &c->u.node.mask;
+
+ if (!memcmp(addr, addr2, 4) &&
+ !memcmp(mask, mask2, 4)) {
+
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = c->u.node6.addr;
+ unsigned int *mask2 = c->u.node6.mask;
+
+ if (!memcmp(addr, addr2, 16) &&
+ !memcmp(mask, mask2, 16)) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ *response = 0;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not check if node %s/%s (%s) exists",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+/* Query a node */
+int sepol_node_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_node_key_t * key, sepol_node_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int proto;
+ const char *addr, *mask;
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = &c->u.node.addr;
+ unsigned int *mask2 = &c->u.node.mask;
+
+ if (!memcmp(addr, addr2, 4) &&
+ !memcmp(mask, mask2, 4)) {
+
+ if (node_to_record(handle, policydb,
+ c, SEPOL_PROTO_IP4,
+ response) < 0)
+ goto err;
+ return STATUS_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ unsigned int *addr2 = c->u.node6.addr;
+ unsigned int *mask2 = c->u.node6.mask;
+
+ if (!memcmp(addr, addr2, 16) &&
+ !memcmp(mask, mask2, 16)) {
+
+ if (node_to_record(handle, policydb,
+ c, SEPOL_PROTO_IP6,
+ response) < 0)
+ goto err;
+ }
+ }
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query node %s/%s (%s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ return STATUS_ERR;
+
+}
+
+/* Load a node into policy */
+int sepol_node_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_node_key_t * key, const sepol_node_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *node = NULL;
+
+ int proto;
+ const char *addr, *mask;
+
+ sepol_node_key_unpack(key, &addr, &mask, &proto);
+
+ if (node_from_record(handle, policydb, &node, data) < 0)
+ goto err;
+
+ switch (proto) {
+
+ case SEPOL_PROTO_IP4:
+ {
+ /* Attach to context list */
+ node->next = policydb->ocontexts[OCON_NODE];
+ policydb->ocontexts[OCON_NODE] = node;
+ break;
+ }
+ case SEPOL_PROTO_IP6:
+ {
+ /* Attach to context list */
+ node->next = policydb->ocontexts[OCON_NODE6];
+ policydb->ocontexts[OCON_NODE6] = node;
+ break;
+ }
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not load node %s/%s (%s)",
+ addr, mask, sepol_node_get_proto_str(proto));
+ if (node != NULL) {
+ context_destroy(&node->context[0]);
+ free(node);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_node_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_node_t * node,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_node_t *node = NULL;
+ int status;
+
+ head = policydb->ocontexts[OCON_NODE];
+ for (c = head; c; c = c->next) {
+ if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
+ < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(node, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_node_free(node);
+ node = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ head = policydb->ocontexts[OCON_NODE6];
+ for (c = head; c; c = c->next) {
+ if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
+ < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(node, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_node_free(node);
+ node = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over nodes");
+ sepol_node_free(node);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/polcaps.c b/libsepol/src/polcaps.c
new file mode 100644
index 0000000..43a71a7
--- /dev/null
+++ b/libsepol/src/polcaps.c
@@ -0,0 +1,35 @@
+/*
+ * Policy capability support functions
+ */
+
+#include <string.h>
+#include <sepol/policydb/polcaps.h>
+
+static const char *polcap_names[] = {
+ "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */
+ "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */
+ "redhat1", /* POLICYDB_CAPABILITY_REDHAT1, aka ptrace_child */
+ "always_check_network", /* POLICYDB_CAPABILITY_ALWAYSNETWORK */
+ NULL
+};
+
+int sepol_polcap_getnum(const char *name)
+{
+ int capnum;
+
+ for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) {
+ if (polcap_names[capnum] == NULL)
+ continue;
+ if (strcasecmp(polcap_names[capnum], name) == 0)
+ return capnum;
+ }
+ return -1;
+}
+
+const char *sepol_polcap_getname(int capnum)
+{
+ if (capnum > POLICYDB_CAPABILITY_MAX)
+ return NULL;
+
+ return polcap_names[capnum];
+}
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
new file mode 100644
index 0000000..6a80f94
--- /dev/null
+++ b/libsepol/src/policydb.c
@@ -0,0 +1,3992 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2005 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the policy database.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/flask.h>
+
+#include "private.h"
+#include "debug.h"
+#include "mls.h"
+
+#define POLICYDB_TARGET_SZ ARRAY_SIZE(policydb_target_strings)
+const char *policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING };
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_XEN_PCIDEVICE + 1,
+ .target_platform = SEPOL_TARGET_XEN,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_XEN_DEVICETREE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_XEN_DEVICETREE + 1,
+ .target_platform = SEPOL_TARGET_XEN,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM - 3,
+ .ocon_num = OCON_FSUSE + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOOL,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_FSUSE + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_IPV6,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_NLCLASS,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_AVTAB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_RANGETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_DEFAULT_TYPE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_KERN,
+ .version = POLICYDB_VERSION_XPERMS_IOCTL,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_MLS_USERS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_TUNABLE_SEP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_BASE,
+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NODE6 + 1,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_MLS_USERS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_ROLEATTRIB,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_TUNABLE_SEP,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+ {
+ .type = POLICY_MOD,
+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = 0,
+ .target_platform = SEPOL_TARGET_SELINUX,
+ },
+};
+
+#if 0
+static char *symtab_name[SYM_NUM] = {
+ "common prefixes",
+ "classes",
+ "roles",
+ "types",
+ "users",
+ "bools" mls_symtab_names cond_symtab_names
+};
+#endif
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+ 2,
+ 32,
+ 16,
+ 512,
+ 128,
+ 16,
+ 16,
+ 16,
+};
+
+struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+ unsigned int type,
+ unsigned int target_platform)
+{
+ unsigned int i;
+ struct policydb_compat_info *info = NULL;
+
+ for (i = 0; i < sizeof(policydb_compat) / sizeof(*info); i++) {
+ if (policydb_compat[i].version == version &&
+ policydb_compat[i].type == type &&
+ policydb_compat[i].target_platform == target_platform) {
+ info = &policydb_compat[i];
+ break;
+ }
+ }
+ return info;
+}
+
+void type_set_init(type_set_t * x)
+{
+ memset(x, 0, sizeof(type_set_t));
+ ebitmap_init(&x->types);
+ ebitmap_init(&x->negset);
+}
+
+void type_set_destroy(type_set_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->types);
+ ebitmap_destroy(&x->negset);
+ }
+}
+
+void role_set_init(role_set_t * x)
+{
+ memset(x, 0, sizeof(role_set_t));
+ ebitmap_init(&x->roles);
+}
+
+void role_set_destroy(role_set_t * x)
+{
+ ebitmap_destroy(&x->roles);
+}
+
+void role_datum_init(role_datum_t * x)
+{
+ memset(x, 0, sizeof(role_datum_t));
+ ebitmap_init(&x->dominates);
+ type_set_init(&x->types);
+ ebitmap_init(&x->cache);
+ ebitmap_init(&x->roles);
+}
+
+void role_datum_destroy(role_datum_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->dominates);
+ type_set_destroy(&x->types);
+ ebitmap_destroy(&x->cache);
+ ebitmap_destroy(&x->roles);
+ }
+}
+
+void type_datum_init(type_datum_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ ebitmap_init(&x->types);
+}
+
+void type_datum_destroy(type_datum_t * x)
+{
+ if (x != NULL) {
+ ebitmap_destroy(&x->types);
+ }
+}
+
+void user_datum_init(user_datum_t * x)
+{
+ memset(x, 0, sizeof(user_datum_t));
+ role_set_init(&x->roles);
+ mls_semantic_range_init(&x->range);
+ mls_semantic_level_init(&x->dfltlevel);
+ ebitmap_init(&x->cache);
+ mls_range_init(&x->exp_range);
+ mls_level_init(&x->exp_dfltlevel);
+}
+
+void user_datum_destroy(user_datum_t * x)
+{
+ if (x != NULL) {
+ role_set_destroy(&x->roles);
+ mls_semantic_range_destroy(&x->range);
+ mls_semantic_level_destroy(&x->dfltlevel);
+ ebitmap_destroy(&x->cache);
+ mls_range_destroy(&x->exp_range);
+ mls_level_destroy(&x->exp_dfltlevel);
+ }
+}
+
+void level_datum_init(level_datum_t * x)
+{
+ memset(x, 0, sizeof(level_datum_t));
+}
+
+void level_datum_destroy(level_datum_t * x __attribute__ ((unused)))
+{
+ /* the mls_level_t referenced by the level_datum is managed
+ * separately for now, so there is nothing to destroy */
+ return;
+}
+
+void cat_datum_init(cat_datum_t * x)
+{
+ memset(x, 0, sizeof(cat_datum_t));
+}
+
+void cat_datum_destroy(cat_datum_t * x __attribute__ ((unused)))
+{
+ /* it's currently a simple struct - really nothing to destroy */
+ return;
+}
+
+void class_perm_node_init(class_perm_node_t * x)
+{
+ memset(x, 0, sizeof(class_perm_node_t));
+}
+
+void avrule_init(avrule_t * x)
+{
+ memset(x, 0, sizeof(avrule_t));
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+}
+
+void avrule_destroy(avrule_t * x)
+{
+ class_perm_node_t *cur, *next;
+
+ if (x == NULL) {
+ return;
+ }
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+
+ free(x->source_filename);
+
+ next = x->perms;
+ while (next) {
+ cur = next;
+ next = cur->next;
+ free(cur);
+ }
+}
+
+void role_trans_rule_init(role_trans_rule_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ role_set_init(&x->roles);
+ type_set_init(&x->types);
+ ebitmap_init(&x->classes);
+}
+
+void role_trans_rule_destroy(role_trans_rule_t * x)
+{
+ if (x != NULL) {
+ role_set_destroy(&x->roles);
+ type_set_destroy(&x->types);
+ ebitmap_destroy(&x->classes);
+ }
+}
+
+void role_trans_rule_list_destroy(role_trans_rule_t * x)
+{
+ while (x != NULL) {
+ role_trans_rule_t *next = x->next;
+ role_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void filename_trans_rule_init(filename_trans_rule_t * x)
+{
+ memset(x, 0, sizeof(*x));
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+}
+
+static void filename_trans_rule_destroy(filename_trans_rule_t * x)
+{
+ if (!x)
+ return;
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+ free(x->name);
+}
+
+void filename_trans_rule_list_destroy(filename_trans_rule_t * x)
+{
+ filename_trans_rule_t *next;
+ while (x) {
+ next = x->next;
+ filename_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void role_allow_rule_init(role_allow_rule_t * x)
+{
+ memset(x, 0, sizeof(role_allow_rule_t));
+ role_set_init(&x->roles);
+ role_set_init(&x->new_roles);
+}
+
+void role_allow_rule_destroy(role_allow_rule_t * x)
+{
+ role_set_destroy(&x->roles);
+ role_set_destroy(&x->new_roles);
+}
+
+void role_allow_rule_list_destroy(role_allow_rule_t * x)
+{
+ while (x != NULL) {
+ role_allow_rule_t *next = x->next;
+ role_allow_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void range_trans_rule_init(range_trans_rule_t * x)
+{
+ type_set_init(&x->stypes);
+ type_set_init(&x->ttypes);
+ ebitmap_init(&x->tclasses);
+ mls_semantic_range_init(&x->trange);
+ x->next = NULL;
+}
+
+void range_trans_rule_destroy(range_trans_rule_t * x)
+{
+ type_set_destroy(&x->stypes);
+ type_set_destroy(&x->ttypes);
+ ebitmap_destroy(&x->tclasses);
+ mls_semantic_range_destroy(&x->trange);
+}
+
+void range_trans_rule_list_destroy(range_trans_rule_t * x)
+{
+ while (x != NULL) {
+ range_trans_rule_t *next = x->next;
+ range_trans_rule_destroy(x);
+ free(x);
+ x = next;
+ }
+}
+
+void avrule_list_destroy(avrule_t * x)
+{
+ avrule_t *next, *cur;
+
+ if (!x)
+ return;
+
+ next = x;
+ while (next) {
+ cur = next;
+ next = next->next;
+ avrule_destroy(cur);
+ free(cur);
+ }
+}
+
+/*
+ * Initialize the role table by implicitly adding role 'object_r'. If
+ * the policy is a module, set object_r's scope to be SCOPE_REQ,
+ * otherwise set it to SCOPE_DECL.
+ */
+static int roles_init(policydb_t * p)
+{
+ char *key = 0;
+ int rc;
+ role_datum_t *role;
+
+ role = calloc(1, sizeof(role_datum_t));
+ if (!role) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ key = malloc(strlen(OBJECT_R) + 1);
+ if (!key) {
+ rc = -ENOMEM;
+ goto out_free_role;
+ }
+ strcpy(key, OBJECT_R);
+ rc = symtab_insert(p, SYM_ROLES, key, role,
+ (p->policy_type ==
+ POLICY_MOD ? SCOPE_REQ : SCOPE_DECL), 1,
+ &role->s.value);
+ if (rc)
+ goto out_free_key;
+ if (role->s.value != OBJECT_R_VAL) {
+ rc = -EINVAL;
+ goto out_free_role;
+ }
+ out:
+ return rc;
+
+ out_free_key:
+ free(key);
+ out_free_role:
+ free(role);
+ goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+int policydb_init(policydb_t * p)
+{
+ int i, rc;
+
+ memset(p, 0, sizeof(policydb_t));
+
+ ebitmap_init(&p->policycaps);
+
+ ebitmap_init(&p->permissive_map);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ p->sym_val_to_name[i] = NULL;
+ rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+ if (rc)
+ goto out_free_symtab;
+ }
+
+ /* initialize the module stuff */
+ for (i = 0; i < SYM_NUM; i++) {
+ if (symtab_init(&p->scope[i], symtab_sizes[i])) {
+ goto out_free_symtab;
+ }
+ }
+ if ((p->global = avrule_block_create()) == NULL ||
+ (p->global->branch_list = avrule_decl_create(1)) == NULL) {
+ goto out_free_symtab;
+ }
+ p->decl_val_to_struct = NULL;
+
+ rc = avtab_init(&p->te_avtab);
+ if (rc)
+ goto out_free_symtab;
+
+ rc = roles_init(p);
+ if (rc)
+ goto out_free_symtab;
+
+ rc = cond_policydb_init(p);
+ if (rc)
+ goto out_free_symtab;
+ out:
+ return rc;
+
+ out_free_symtab:
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_destroy(p->symtab[i].table);
+ hashtab_destroy(p->scope[i].table);
+ }
+ avrule_block_list_destroy(p->global);
+ goto out;
+}
+
+int policydb_role_cache(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *arg)
+{
+ policydb_t *p;
+ role_datum_t *role;
+
+ role = (role_datum_t *) datum;
+ p = (policydb_t *) arg;
+
+ ebitmap_destroy(&role->cache);
+ if (type_set_expand(&role->types, &role->cache, p, 1)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int policydb_user_cache(hashtab_key_t key
+ __attribute__ ((unused)), hashtab_datum_t datum,
+ void *arg)
+{
+ policydb_t *p;
+ user_datum_t *user;
+
+ user = (user_datum_t *) datum;
+ p = (policydb_t *) arg;
+
+ ebitmap_destroy(&user->cache);
+ if (role_set_expand(&user->roles, &user->cache, p, NULL, NULL)) {
+ return -1;
+ }
+
+ /* we do not expand user's MLS info in kernel policies because the
+ * semantic representation is not present and we do not expand user's
+ * MLS info in module policies because all of the necessary mls
+ * information is not present */
+ if (p->policy_type != POLICY_KERN && p->policy_type != POLICY_MOD) {
+ mls_range_destroy(&user->exp_range);
+ if (mls_semantic_range_expand(&user->range,
+ &user->exp_range, p, NULL)) {
+ return -1;
+ }
+
+ mls_level_destroy(&user->exp_dfltlevel);
+ if (mls_semantic_level_expand(&user->dfltlevel,
+ &user->exp_dfltlevel, p, NULL)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure. The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations. The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ common_datum_t *comdatum;
+
+ comdatum = (common_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!comdatum->s.value || comdatum->s.value > p->p_commons.nprim)
+ return -EINVAL;
+ p->p_common_val_to_name[comdatum->s.value - 1] = (char *)key;
+
+ return 0;
+}
+
+static int class_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ class_datum_t *cladatum;
+
+ cladatum = (class_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!cladatum->s.value || cladatum->s.value > p->p_classes.nprim)
+ return -EINVAL;
+ p->p_class_val_to_name[cladatum->s.value - 1] = (char *)key;
+ p->class_val_to_struct[cladatum->s.value - 1] = cladatum;
+
+ return 0;
+}
+
+static int role_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ role_datum_t *role;
+
+ role = (role_datum_t *) datum;
+ p = (policydb_t *) datap;
+ if (!role->s.value || role->s.value > p->p_roles.nprim)
+ return -EINVAL;
+ p->p_role_val_to_name[role->s.value - 1] = (char *)key;
+ p->role_val_to_struct[role->s.value - 1] = role;
+
+ return 0;
+}
+
+static int type_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ type_datum_t *typdatum;
+
+ typdatum = (type_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (typdatum->primary) {
+ if (!typdatum->s.value || typdatum->s.value > p->p_types.nprim)
+ return -EINVAL;
+ p->p_type_val_to_name[typdatum->s.value - 1] = (char *)key;
+ p->type_val_to_struct[typdatum->s.value - 1] = typdatum;
+ }
+
+ return 0;
+}
+
+static int user_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ user_datum_t *usrdatum;
+
+ usrdatum = (user_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!usrdatum->s.value || usrdatum->s.value > p->p_users.nprim)
+ return -EINVAL;
+
+ p->p_user_val_to_name[usrdatum->s.value - 1] = (char *)key;
+ p->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+
+ return 0;
+}
+
+static int sens_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ level_datum_t *levdatum;
+
+ levdatum = (level_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!levdatum->isalias) {
+ if (!levdatum->level->sens ||
+ levdatum->level->sens > p->p_levels.nprim)
+ return -EINVAL;
+ p->p_sens_val_to_name[levdatum->level->sens - 1] = (char *)key;
+ }
+
+ return 0;
+}
+
+static int cat_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
+{
+ policydb_t *p;
+ cat_datum_t *catdatum;
+
+ catdatum = (cat_datum_t *) datum;
+ p = (policydb_t *) datap;
+
+ if (!catdatum->isalias) {
+ if (!catdatum->s.value || catdatum->s.value > p->p_cats.nprim)
+ return -EINVAL;
+ p->p_cat_val_to_name[catdatum->s.value - 1] = (char *)key;
+ }
+
+ return 0;
+}
+
+static int (*index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_index, class_index, role_index, type_index, user_index,
+ cond_index_bool, sens_index, cat_index,};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.
+ */
+int policydb_index_classes(policydb_t * p)
+{
+ free(p->p_common_val_to_name);
+ p->p_common_val_to_name = (char **)
+ malloc(p->p_commons.nprim * sizeof(char *));
+ if (!p->p_common_val_to_name)
+ return -1;
+
+ if (hashtab_map(p->p_commons.table, common_index, p))
+ return -1;
+
+ free(p->class_val_to_struct);
+ p->class_val_to_struct = (class_datum_t **)
+ malloc(p->p_classes.nprim * sizeof(class_datum_t *));
+ if (!p->class_val_to_struct)
+ return -1;
+
+ free(p->p_class_val_to_name);
+ p->p_class_val_to_name = (char **)
+ malloc(p->p_classes.nprim * sizeof(char *));
+ if (!p->p_class_val_to_name)
+ return -1;
+
+ if (hashtab_map(p->p_classes.table, class_index, p))
+ return -1;
+
+ return 0;
+}
+
+int policydb_index_bools(policydb_t * p)
+{
+
+ if (cond_init_bool_indexes(p) == -1)
+ return -1;
+ p->p_bool_val_to_name = (char **)
+ malloc(p->p_bools.nprim * sizeof(char *));
+ if (!p->p_bool_val_to_name)
+ return -1;
+ if (hashtab_map(p->p_bools.table, cond_index_bool, p))
+ return -1;
+ return 0;
+}
+
+int policydb_index_decls(policydb_t * p)
+{
+ avrule_block_t *curblock;
+ avrule_decl_t *decl;
+ int num_decls = 0;
+
+ free(p->decl_val_to_struct);
+
+ for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+ for (decl = curblock->branch_list; decl != NULL;
+ decl = decl->next) {
+ num_decls++;
+ }
+ }
+
+ p->decl_val_to_struct =
+ calloc(num_decls, sizeof(*(p->decl_val_to_struct)));
+ if (!p->decl_val_to_struct) {
+ return -1;
+ }
+
+ for (curblock = p->global; curblock != NULL; curblock = curblock->next) {
+ for (decl = curblock->branch_list; decl != NULL;
+ decl = decl->next) {
+ p->decl_val_to_struct[decl->decl_id - 1] = decl;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.
+ */
+int policydb_index_others(sepol_handle_t * handle,
+ policydb_t * p, unsigned verbose)
+{
+ int i;
+
+ if (verbose) {
+ INFO(handle,
+ "security: %d users, %d roles, %d types, %d bools",
+ p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
+ p->p_bools.nprim);
+
+ if (p->mls)
+ INFO(handle, "security: %d sens, %d cats",
+ p->p_levels.nprim, p->p_cats.nprim);
+
+ INFO(handle, "security: %d classes, %d rules, %d cond rules",
+ p->p_classes.nprim, p->te_avtab.nel, p->te_cond_avtab.nel);
+ }
+#if 0
+ avtab_hash_eval(&p->te_avtab, "rules");
+ for (i = 0; i < SYM_NUM; i++)
+ hashtab_hash_eval(p->symtab[i].table, symtab_name[i]);
+#endif
+
+ free(p->role_val_to_struct);
+ p->role_val_to_struct = (role_datum_t **)
+ malloc(p->p_roles.nprim * sizeof(role_datum_t *));
+ if (!p->role_val_to_struct)
+ return -1;
+
+ free(p->user_val_to_struct);
+ p->user_val_to_struct = (user_datum_t **)
+ malloc(p->p_users.nprim * sizeof(user_datum_t *));
+ if (!p->user_val_to_struct)
+ return -1;
+
+ free(p->type_val_to_struct);
+ p->type_val_to_struct = (type_datum_t **)
+ calloc(p->p_types.nprim, sizeof(type_datum_t *));
+ if (!p->type_val_to_struct)
+ return -1;
+
+ cond_init_bool_indexes(p);
+
+ for (i = SYM_ROLES; i < SYM_NUM; i++) {
+ free(p->sym_val_to_name[i]);
+ p->sym_val_to_name[i] = NULL;
+ if (p->symtab[i].nprim) {
+ p->sym_val_to_name[i] = (char **)
+ calloc(p->symtab[i].nprim, sizeof(char *));
+ if (!p->sym_val_to_name[i])
+ return -1;
+ if (hashtab_map(p->symtab[i].table, index_f[i], p))
+ return -1;
+ }
+ }
+
+ /* This pre-expands the roles and users for context validity checking */
+ if (hashtab_map(p->p_roles.table, policydb_role_cache, p))
+ return -1;
+
+ if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ free(datum);
+ return 0;
+}
+
+static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ common_datum_t *comdatum;
+
+ if (key)
+ free(key);
+ comdatum = (common_datum_t *) datum;
+ (void)hashtab_map(comdatum->permissions.table, perm_destroy, 0);
+ hashtab_destroy(comdatum->permissions.table);
+ free(datum);
+ return 0;
+}
+
+static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ class_datum_t *cladatum;
+ constraint_node_t *constraint, *ctemp;
+ constraint_expr_t *e, *etmp;
+
+ if (key)
+ free(key);
+ cladatum = (class_datum_t *) datum;
+ if (cladatum == NULL) {
+ return 0;
+ }
+ (void)hashtab_map(cladatum->permissions.table, perm_destroy, 0);
+ hashtab_destroy(cladatum->permissions.table);
+ constraint = cladatum->constraints;
+ while (constraint) {
+ e = constraint->expr;
+ while (e) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ free(ctemp);
+ }
+
+ constraint = cladatum->validatetrans;
+ while (constraint) {
+ e = constraint->expr;
+ while (e) {
+ etmp = e;
+ e = e->next;
+ constraint_expr_destroy(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ free(ctemp);
+ }
+
+ if (cladatum->comkey)
+ free(cladatum->comkey);
+ free(datum);
+ return 0;
+}
+
+static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ role_datum_destroy((role_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ type_datum_destroy((type_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ free(key);
+ user_datum_destroy((user_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ level_datum_t *levdatum;
+
+ if (key)
+ free(key);
+ levdatum = (level_datum_t *) datum;
+ mls_level_destroy(levdatum->level);
+ free(levdatum->level);
+ level_datum_destroy(levdatum);
+ free(levdatum);
+ return 0;
+}
+
+static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ cat_datum_destroy((cat_datum_t *) datum);
+ free(datum);
+ return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
+ cond_destroy_bool, sens_destroy, cat_destroy,};
+
+void ocontext_selinux_free(ocontext_t **ocontexts)
+{
+ ocontext_t *c, *ctmp;
+ int i;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ c = ocontexts[i];
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ context_destroy(&ctmp->context[1]);
+ if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF
+ || i == OCON_FSUSE)
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ }
+}
+
+void ocontext_xen_free(ocontext_t **ocontexts)
+{
+ ocontext_t *c, *ctmp;
+ int i;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ c = ocontexts[i];
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ context_destroy(&ctmp->context[1]);
+ if (i == OCON_ISID || i == OCON_XEN_DEVICETREE)
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ }
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(policydb_t * p)
+{
+ ocontext_t *c, *ctmp;
+ genfs_t *g, *gtmp;
+ unsigned int i;
+ role_allow_t *ra, *lra = NULL;
+ role_trans_t *tr, *ltr = NULL;
+ range_trans_t *rt, *lrt = NULL;
+ filename_trans_t *ft, *nft;
+
+ if (!p)
+ return;
+
+ ebitmap_destroy(&p->policycaps);
+
+ ebitmap_destroy(&p->permissive_map);
+
+ symtabs_destroy(p->symtab);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ if (p->sym_val_to_name[i])
+ free(p->sym_val_to_name[i]);
+ }
+
+ if (p->class_val_to_struct)
+ free(p->class_val_to_struct);
+ if (p->role_val_to_struct)
+ free(p->role_val_to_struct);
+ if (p->user_val_to_struct)
+ free(p->user_val_to_struct);
+ if (p->type_val_to_struct)
+ free(p->type_val_to_struct);
+ free(p->decl_val_to_struct);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ (void)hashtab_map(p->scope[i].table, scope_destroy, 0);
+ hashtab_destroy(p->scope[i].table);
+ }
+ avrule_block_list_destroy(p->global);
+ free(p->name);
+ free(p->version);
+
+ avtab_destroy(&p->te_avtab);
+
+ if (p->target_platform == SEPOL_TARGET_SELINUX)
+ ocontext_selinux_free(p->ocontexts);
+ else if (p->target_platform == SEPOL_TARGET_XEN)
+ ocontext_xen_free(p->ocontexts);
+
+ g = p->genfs;
+ while (g) {
+ free(g->fstype);
+ c = g->head;
+ while (c) {
+ ctmp = c;
+ c = c->next;
+ context_destroy(&ctmp->context[0]);
+ free(ctmp->u.name);
+ free(ctmp);
+ }
+ gtmp = g;
+ g = g->next;
+ free(gtmp);
+ }
+ cond_policydb_destroy(p);
+
+ for (tr = p->role_tr; tr; tr = tr->next) {
+ if (ltr)
+ free(ltr);
+ ltr = tr;
+ }
+ if (ltr)
+ free(ltr);
+
+ ft = p->filename_trans;
+ while (ft) {
+ nft = ft->next;
+ free(ft->name);
+ free(ft);
+ ft = nft;
+ }
+
+ for (ra = p->role_allow; ra; ra = ra->next) {
+ if (lra)
+ free(lra);
+ lra = ra;
+ }
+ if (lra)
+ free(lra);
+
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ lrt = rt;
+ }
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+
+ if (p->type_attr_map) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_destroy(&p->type_attr_map[i]);
+ }
+ free(p->type_attr_map);
+ }
+
+ if (p->attr_type_map) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_destroy(&p->attr_type_map[i]);
+ }
+ free(p->attr_type_map);
+ }
+
+ return;
+}
+
+void symtabs_destroy(symtab_t * symtab)
+{
+ int i;
+ for (i = 0; i < SYM_NUM; i++) {
+ (void)hashtab_map(symtab[i].table, destroy_f[i], 0);
+ hashtab_destroy(symtab[i].table);
+ }
+}
+
+int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+ __attribute__ ((unused)))
+{
+ scope_datum_t *cur = (scope_datum_t *) datum;
+ free(key);
+ if (cur != NULL) {
+ free(cur->decl_ids);
+ }
+ free(cur);
+ return 0;
+}
+
+hashtab_destroy_func_t get_symtab_destroy_func(int sym_num)
+{
+ if (sym_num < 0 || sym_num >= SYM_NUM) {
+ return NULL;
+ }
+ return (hashtab_destroy_func_t) destroy_f[sym_num];
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(policydb_t * p, sidtab_t * s)
+{
+ ocontext_t *head, *c;
+
+ if (sepol_sidtab_init(s)) {
+ ERR(NULL, "out of memory on SID table init");
+ return -1;
+ }
+
+ head = p->ocontexts[OCON_ISID];
+ for (c = head; c; c = c->next) {
+ if (!c->context[0].user) {
+ ERR(NULL, "SID %s was never defined", c->u.name);
+ return -1;
+ }
+ if (sepol_sidtab_insert(s, c->sid[0], &c->context[0])) {
+ ERR(NULL, "unable to load initial SID %s", c->u.name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Declare a symbol for a certain avrule_block context. Insert it
+ * into a symbol table for a policy. This function will handle
+ * inserting the appropriate scope information in addition to
+ * inserting the symbol into the hash table.
+ *
+ * arguments:
+ * policydb_t *pol module policy to modify
+ * uint32_t sym the symbole table for insertion (SYM_*)
+ * hashtab_key_t key the key for the symbol - not cloned
+ * hashtab_datum_t data the data for the symbol - not cloned
+ * scope scope of this symbol, either SCOPE_REQ or SCOPE_DECL
+ * avrule_decl_id identifier for this symbol's encapsulating declaration
+ * value (out) assigned value to the symbol (if value is not NULL)
+ *
+ * returns:
+ * 0 success
+ * 1 success, but symbol already existed as a requirement
+ * (datum was not inserted and needs to be free()d)
+ * -1 general error
+ * -2 scope conflicted
+ * -ENOMEM memory error
+ * error codes from hashtab_insert
+ */
+int symtab_insert(policydb_t * pol, uint32_t sym,
+ hashtab_key_t key, hashtab_datum_t datum,
+ uint32_t scope, uint32_t avrule_decl_id, uint32_t * value)
+{
+ int rc, retval = 0;
+ unsigned int i;
+ scope_datum_t *scope_datum;
+
+ /* check if the symbol is already there. multiple
+ * declarations of non-roles/non-users are illegal, but
+ * multiple requires are allowed. */
+
+ /* FIX ME - the failures after the hashtab_insert will leave
+ * the policy in a inconsistent state. */
+ rc = hashtab_insert(pol->symtab[sym].table, key, datum);
+ if (rc == SEPOL_OK) {
+ /* if no value is passed in the symbol is not primary
+ * (i.e. aliases) */
+ if (value)
+ *value = ++pol->symtab[sym].nprim;
+ } else if (rc == SEPOL_EEXIST) {
+ retval = 1; /* symbol not added -- need to free() later */
+ } else {
+ return rc;
+ }
+
+ /* get existing scope information; if there is not one then
+ * create it */
+ scope_datum =
+ (scope_datum_t *) hashtab_search(pol->scope[sym].table, key);
+ if (scope_datum == NULL) {
+ hashtab_key_t key2 = strdup((char *)key);
+ if (!key2)
+ return -ENOMEM;
+ if ((scope_datum = malloc(sizeof(*scope_datum))) == NULL) {
+ free(key2);
+ return -ENOMEM;
+ }
+ scope_datum->scope = scope;
+ scope_datum->decl_ids = NULL;
+ scope_datum->decl_ids_len = 0;
+ if ((rc =
+ hashtab_insert(pol->scope[sym].table, key2,
+ scope_datum)) != 0) {
+ free(key2);
+ free(scope_datum);
+ return rc;
+ }
+ } else if (scope_datum->scope == SCOPE_DECL && scope == SCOPE_DECL) {
+ /* disallow multiple declarations for non-roles/users */
+ if (sym != SYM_ROLES && sym != SYM_USERS) {
+ return -2;
+ }
+ /* Further confine that a role attribute can't have the same
+ * name as another regular role, and a role attribute can't
+ * be declared more than once. */
+ if (sym == SYM_ROLES) {
+ role_datum_t *base_role;
+ role_datum_t *cur_role = (role_datum_t *)datum;
+
+ base_role = (role_datum_t *)
+ hashtab_search(pol->symtab[sym].table,
+ key);
+ assert(base_role != NULL);
+
+ if (!((base_role->flavor == ROLE_ROLE) &&
+ (cur_role->flavor == ROLE_ROLE))) {
+ /* Only regular roles are allowed to have
+ * multiple declarations. */
+ return -2;
+ }
+ }
+ } else if (scope_datum->scope == SCOPE_REQ && scope == SCOPE_DECL) {
+ scope_datum->scope = SCOPE_DECL;
+ } else if (scope_datum->scope != scope) {
+ /* This only happens in DECL then REQUIRE case, which is handled by caller */
+ return -2;
+ }
+
+ /* search through the pre-existing list to avoid adding duplicates */
+ for (i = 0; i < scope_datum->decl_ids_len; i++) {
+ if (scope_datum->decl_ids[i] == avrule_decl_id) {
+ /* already there, so don't modify its scope */
+ return retval;
+ }
+ }
+
+ if (add_i_to_a(avrule_decl_id,
+ &scope_datum->decl_ids_len,
+ &scope_datum->decl_ids) == -1) {
+ return -ENOMEM;
+ }
+
+ return retval;
+}
+
+int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b)
+{
+ type_set_init(dst);
+
+ if (ebitmap_or(&dst->types, &a->types, &b->types)) {
+ return -1;
+ }
+ if (ebitmap_or(&dst->negset, &a->negset, &b->negset)) {
+ return -1;
+ }
+
+ dst->flags |= a->flags;
+ dst->flags |= b->flags;
+
+ return 0;
+}
+
+int type_set_cpy(type_set_t * dst, type_set_t * src)
+{
+ type_set_init(dst);
+
+ dst->flags = src->flags;
+ if (ebitmap_cpy(&dst->types, &src->types))
+ return -1;
+ if (ebitmap_cpy(&dst->negset, &src->negset))
+ return -1;
+
+ return 0;
+}
+
+int type_set_or_eq(type_set_t * dst, type_set_t * other)
+{
+ int ret;
+ type_set_t tmp;
+
+ if (type_set_or(&tmp, dst, other))
+ return -1;
+ type_set_destroy(dst);
+ ret = type_set_cpy(dst, &tmp);
+ type_set_destroy(&tmp);
+
+ return ret;
+}
+
+int role_set_get_role(role_set_t * x, uint32_t role)
+{
+ if (x->flags & ROLE_STAR)
+ return 1;
+
+ if (ebitmap_get_bit(&x->roles, role - 1)) {
+ if (x->flags & ROLE_COMP)
+ return 0;
+ else
+ return 1;
+ } else {
+ if (x->flags & ROLE_COMP)
+ return 1;
+ else
+ return 0;
+ }
+}
+
+/***********************************************************************/
+/* everything below is for policy reads */
+
+/* The following are read functions for module structures */
+
+static int role_set_read(role_set_t * r, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ if (ebitmap_read(&r->roles, fp))
+ return -1;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ r->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+static int type_set_read(type_set_t * t, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ if (ebitmap_read(&t->types, fp))
+ return -1;
+ if (ebitmap_read(&t->negset, fp))
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ t->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+ uint32_t buf[2], items;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto out;
+
+ items = le32_to_cpu(buf[0]);
+ if (items > ARRAY_SIZE(buf)) {
+ ERR(fp->handle, "range overflow");
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * items);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated range");
+ goto out;
+ }
+ r->level[0].sens = le32_to_cpu(buf[0]);
+ if (items > 1)
+ r->level[1].sens = le32_to_cpu(buf[1]);
+ else
+ r->level[1].sens = r->level[0].sens;
+
+ rc = ebitmap_read(&r->level[0].cat, fp);
+ if (rc) {
+ ERR(fp->handle, "error reading low categories");
+ goto out;
+ }
+ if (items > 1) {
+ rc = ebitmap_read(&r->level[1].cat, fp);
+ if (rc) {
+ ERR(fp->handle, "error reading high categories");
+ goto bad_high;
+ }
+ } else {
+ rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+ if (rc) {
+ ERR(fp->handle, "out of memory");
+ goto bad_high;
+ }
+ }
+
+ rc = 0;
+ out:
+ return rc;
+ bad_high:
+ ebitmap_destroy(&r->level[0].cat);
+ goto out;
+}
+
+/*
+ * Read a semantic MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_semantic_level_helper(mls_semantic_level_t * l,
+ struct policy_file *fp)
+{
+ uint32_t buf[2], ncat;
+ unsigned int i;
+ mls_semantic_cat_t *cat;
+ int rc;
+
+ mls_semantic_level_init(l);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated level");
+ goto bad;
+ }
+ l->sens = le32_to_cpu(buf[0]);
+
+ ncat = le32_to_cpu(buf[1]);
+ for (i = 0; i < ncat; i++) {
+ cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!cat) {
+ ERR(fp->handle, "out of memory");
+ goto bad;
+ }
+
+ mls_semantic_cat_init(cat);
+ cat->next = l->cat;
+ l->cat = cat;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ ERR(fp->handle, "error reading level categories");
+ goto bad;
+ }
+ cat->low = le32_to_cpu(buf[0]);
+ cat->high = le32_to_cpu(buf[1]);
+ }
+
+ return 0;
+
+ bad:
+ return -EINVAL;
+}
+
+/*
+ * Read a semantic MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_semantic_range_helper(mls_semantic_range_t * r,
+ struct policy_file *fp)
+{
+ int rc;
+
+ rc = mls_read_semantic_level_helper(&r->level[0], fp);
+ if (rc)
+ return rc;
+
+ rc = mls_read_semantic_level_helper(&r->level[1], fp);
+
+ return rc;
+}
+
+static int mls_level_to_semantic(mls_level_t * l, mls_semantic_level_t * sl)
+{
+ unsigned int i;
+ ebitmap_node_t *cnode;
+ mls_semantic_cat_t *open_cat = NULL;
+
+ mls_semantic_level_init(sl);
+ sl->sens = l->sens;
+ ebitmap_for_each_bit(&l->cat, cnode, i) {
+ if (ebitmap_node_get_bit(cnode, i)) {
+ if (open_cat)
+ continue;
+ open_cat = (mls_semantic_cat_t *)
+ malloc(sizeof(mls_semantic_cat_t));
+ if (!open_cat)
+ return -1;
+
+ mls_semantic_cat_init(open_cat);
+ open_cat->low = i + 1;
+ open_cat->next = sl->cat;
+ sl->cat = open_cat;
+ } else {
+ if (!open_cat)
+ continue;
+ open_cat->high = i;
+ open_cat = NULL;
+ }
+ }
+ if (open_cat)
+ open_cat->high = i;
+
+ return 0;
+}
+
+static int mls_range_to_semantic(mls_range_t * r, mls_semantic_range_t * sr)
+{
+ if (mls_level_to_semantic(&r->level[0], &sr->level[0]))
+ return -1;
+
+ if (mls_level_to_semantic(&r->level[1], &sr->level[1]))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(context_struct_t * c,
+ policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[3];
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0) {
+ ERR(fp->handle, "context truncated");
+ return -1;
+ }
+ c->user = le32_to_cpu(buf[0]);
+ c->role = le32_to_cpu(buf[1]);
+ c->type = le32_to_cpu(buf[2]);
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS)) {
+ if (mls_read_range_helper(&c->range, fp)) {
+ ERR(fp->handle, "error reading MLS range "
+ "of context");
+ return -1;
+ }
+ }
+
+ if (!policydb_context_isvalid(p, c)) {
+ ERR(fp->handle, "invalid security context");
+ context_destroy(c);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ perm_datum_t *perdatum;
+ uint32_t buf[2];
+ size_t len;
+ int rc;
+
+ perdatum = calloc(1, sizeof(perm_datum_t));
+ if (!perdatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ perdatum->s.value = le32_to_cpu(buf[1]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, perdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ perm_destroy(key, perdatum, NULL);
+ return -1;
+}
+
+static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ common_datum_t *comdatum;
+ uint32_t buf[4];
+ size_t len, nel;
+ unsigned int i;
+ int rc;
+
+ comdatum = calloc(1, sizeof(common_datum_t));
+ if (!comdatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ comdatum->s.value = le32_to_cpu(buf[1]);
+
+ if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
+ goto bad;
+ comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+ nel = le32_to_cpu(buf[3]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ for (i = 0; i < nel; i++) {
+ if (perm_read(p, comdatum->permissions.table, fp))
+ goto bad;
+ }
+
+ if (hashtab_insert(h, key, comdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ common_destroy(key, comdatum, NULL);
+ return -1;
+}
+
+static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep,
+ unsigned int ncons,
+ int allowxtarget, struct policy_file *fp)
+{
+ constraint_node_t *c, *lc;
+ constraint_expr_t *e, *le;
+ uint32_t buf[3];
+ size_t nexpr;
+ unsigned int i, j;
+ int rc, depth;
+
+ lc = NULL;
+ for (i = 0; i < ncons; i++) {
+ c = calloc(1, sizeof(constraint_node_t));
+ if (!c)
+ return -1;
+
+ if (lc)
+ lc->next = c;
+ else
+ *nodep = c;
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ return -1;
+ c->permissions = le32_to_cpu(buf[0]);
+ nexpr = le32_to_cpu(buf[1]);
+ le = NULL;
+ depth = -1;
+ for (j = 0; j < nexpr; j++) {
+ e = malloc(sizeof(constraint_expr_t));
+ if (!e)
+ return -1;
+ if (constraint_expr_init(e) == -1) {
+ free(e);
+ return -1;
+ }
+ if (le) {
+ le->next = e;
+ } else {
+ c->expr = e;
+ }
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+ if (rc < 0)
+ return -1;
+ e->expr_type = le32_to_cpu(buf[0]);
+ e->attr = le32_to_cpu(buf[1]);
+ e->op = le32_to_cpu(buf[2]);
+
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ if (depth < 0)
+ return -1;
+ break;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ if (depth < 1)
+ return -1;
+ depth--;
+ break;
+ case CEXPR_ATTR:
+ if (depth == (CEXPR_MAXDEPTH - 1))
+ return -1;
+ depth++;
+ break;
+ case CEXPR_NAMES:
+ if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+ return -1;
+ if (depth == (CEXPR_MAXDEPTH - 1))
+ return -1;
+ depth++;
+ if (ebitmap_read(&e->names, fp))
+ return -1;
+ if (p->policy_type != POLICY_KERN &&
+ type_set_read(e->type_names, fp))
+ return -1;
+ else if (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
+ type_set_read(e->type_names, fp))
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ le = e;
+ }
+ if (depth != 0)
+ return -1;
+ lc = c;
+ }
+
+ return 0;
+}
+
+static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ class_datum_t *cladatum;
+ uint32_t buf[6];
+ size_t len, len2, ncons, nel;
+ unsigned int i;
+ int rc;
+
+ cladatum = (class_datum_t *) calloc(1, sizeof(class_datum_t));
+ if (!cladatum)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 6);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ len2 = le32_to_cpu(buf[1]);
+ cladatum->s.value = le32_to_cpu(buf[2]);
+
+ if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
+ goto bad;
+ cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+ nel = le32_to_cpu(buf[4]);
+
+ ncons = le32_to_cpu(buf[5]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (len2) {
+ cladatum->comkey = malloc(len2 + 1);
+ if (!cladatum->comkey)
+ goto bad;
+ rc = next_entry(cladatum->comkey, fp, len2);
+ if (rc < 0)
+ goto bad;
+ cladatum->comkey[len2] = 0;
+
+ cladatum->comdatum = hashtab_search(p->p_commons.table,
+ cladatum->comkey);
+ if (!cladatum->comdatum) {
+ ERR(fp->handle, "unknown common %s", cladatum->comkey);
+ goto bad;
+ }
+ }
+ for (i = 0; i < nel; i++) {
+ if (perm_read(p, cladatum->permissions.table, fp))
+ goto bad;
+ }
+
+ if (read_cons_helper(p, &cladatum->constraints, ncons, 0, fp))
+ goto bad;
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+ /* grab the validatetrans rules */
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ ncons = le32_to_cpu(buf[0]);
+ if (read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp))
+ goto bad;
+ }
+
+ if ((p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) ||
+ (p->policy_type == POLICY_BASE &&
+ p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto bad;
+ cladatum->default_user = le32_to_cpu(buf[0]);
+ cladatum->default_role = le32_to_cpu(buf[1]);
+ cladatum->default_range = le32_to_cpu(buf[2]);
+ }
+
+ if ((p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
+ (p->policy_type == POLICY_BASE &&
+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ cladatum->default_type = le32_to_cpu(buf[0]);
+ }
+
+ if (hashtab_insert(h, key, cladatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ class_destroy(key, cladatum, NULL);
+ return -1;
+}
+
+static int role_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ role_datum_t *role;
+ uint32_t buf[3];
+ size_t len;
+ int rc, to_read = 2;
+
+ role = calloc(1, sizeof(role_datum_t));
+ if (!role)
+ return -1;
+
+ if (policydb_has_boundary_feature(p))
+ to_read = 3;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ role->s.value = le32_to_cpu(buf[1]);
+ if (policydb_has_boundary_feature(p))
+ role->bounds = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (ebitmap_read(&role->dominates, fp))
+ goto bad;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&role->types.types, fp))
+ goto bad;
+ } else {
+ if (type_set_read(&role->types, fp))
+ goto bad;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+
+ role->flavor = le32_to_cpu(buf[0]);
+
+ if (ebitmap_read(&role->roles, fp))
+ goto bad;
+ }
+
+ if (strcmp(key, OBJECT_R) == 0) {
+ if (role->s.value != OBJECT_R_VAL) {
+ ERR(fp->handle, "role %s has wrong value %d",
+ OBJECT_R, role->s.value);
+ role_destroy(key, role, NULL);
+ return -1;
+ }
+ role_destroy(key, role, NULL);
+ return 0;
+ }
+
+ if (hashtab_insert(h, key, role))
+ goto bad;
+
+ return 0;
+
+ bad:
+ role_destroy(key, role, NULL);
+ return -1;
+}
+
+static int type_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ type_datum_t *typdatum;
+ uint32_t buf[5];
+ size_t len;
+ int rc, to_read;
+ int pos = 0;
+
+ typdatum = calloc(1, sizeof(type_datum_t));
+ if (!typdatum)
+ return -1;
+
+ if (policydb_has_boundary_feature(p)) {
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS)
+ to_read = 5;
+ else
+ to_read = 4;
+ }
+ else if (p->policy_type == POLICY_KERN)
+ to_read = 3;
+ else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ to_read = 5;
+ else
+ to_read = 4;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[pos]);
+ typdatum->s.value = le32_to_cpu(buf[++pos]);
+ if (policydb_has_boundary_feature(p)) {
+ uint32_t properties;
+
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+ typdatum->primary = le32_to_cpu(buf[++pos]);
+ properties = le32_to_cpu(buf[++pos]);
+ }
+ else {
+ properties = le32_to_cpu(buf[++pos]);
+
+ if (properties & TYPEDATUM_PROPERTY_PRIMARY)
+ typdatum->primary = 1;
+ }
+
+ if (properties & TYPEDATUM_PROPERTY_ATTRIBUTE)
+ typdatum->flavor = TYPE_ATTRIB;
+ if (properties & TYPEDATUM_PROPERTY_ALIAS
+ && p->policy_type != POLICY_KERN)
+ typdatum->flavor = TYPE_ALIAS;
+ if (properties & TYPEDATUM_PROPERTY_PERMISSIVE
+ && p->policy_type != POLICY_KERN)
+ typdatum->flags |= TYPE_FLAGS_PERMISSIVE;
+
+ typdatum->bounds = le32_to_cpu(buf[++pos]);
+ } else {
+ typdatum->primary = le32_to_cpu(buf[++pos]);
+ if (p->policy_type != POLICY_KERN) {
+ typdatum->flavor = le32_to_cpu(buf[++pos]);
+ if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ typdatum->flags = le32_to_cpu(buf[++pos]);
+ }
+ }
+
+ if (p->policy_type != POLICY_KERN) {
+ if (ebitmap_read(&typdatum->types, fp))
+ goto bad;
+ }
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, typdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ type_destroy(key, typdatum, NULL);
+ return -1;
+}
+
+int role_trans_read(policydb_t *p, struct policy_file *fp)
+{
+ role_trans_t **t = &p->role_tr;
+ unsigned int i;
+ uint32_t buf[3], nel;
+ role_trans_t *tr, *ltr;
+ int rc;
+ int new_roletr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ ltr = NULL;
+ for (i = 0; i < nel; i++) {
+ tr = calloc(1, sizeof(struct role_trans));
+ if (!tr) {
+ return -1;
+ }
+ if (ltr) {
+ ltr->next = tr;
+ } else {
+ *t = tr;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ return -1;
+ tr->role = le32_to_cpu(buf[0]);
+ tr->type = le32_to_cpu(buf[1]);
+ tr->new_role = le32_to_cpu(buf[2]);
+ if (new_roletr) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ tr->tclass = le32_to_cpu(buf[0]);
+ } else
+ tr->tclass = SECCLASS_PROCESS;
+ ltr = tr;
+ }
+ return 0;
+}
+
+int role_allow_read(role_allow_t ** r, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[2], nel;
+ role_allow_t *ra, *lra;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lra = NULL;
+ for (i = 0; i < nel; i++) {
+ ra = calloc(1, sizeof(struct role_allow));
+ if (!ra) {
+ return -1;
+ }
+ if (lra) {
+ lra->next = ra;
+ } else {
+ *r = ra;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ ra->role = le32_to_cpu(buf[0]);
+ ra->new_role = le32_to_cpu(buf[1]);
+ lra = ra;
+ }
+ return 0;
+}
+
+int filename_trans_read(filename_trans_t **t, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[4], nel, len;
+ filename_trans_t *ft, *lft;
+ int rc;
+ char *name;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+
+ lft = NULL;
+ for (i = 0; i < nel; i++) {
+ ft = calloc(1, sizeof(struct filename_trans));
+ if (!ft)
+ return -1;
+ if (lft)
+ lft->next = ft;
+ else
+ *t = ft;
+ lft = ft;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ len = le32_to_cpu(buf[0]);
+
+ name = calloc(len + 1, sizeof(*name));
+ if (!name)
+ return -1;
+
+ ft->name = name;
+
+ rc = next_entry(name, fp, len);
+ if (rc < 0)
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+ if (rc < 0)
+ return -1;
+
+ ft->stype = le32_to_cpu(buf[0]);
+ ft->ttype = le32_to_cpu(buf[1]);
+ ft->tclass = le32_to_cpu(buf[2]);
+ ft->otype = le32_to_cpu(buf[3]);
+ }
+ return 0;
+}
+
+static int ocontext_read_xen(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, len;
+ ocontext_t *l, *c;
+ uint32_t buf[8];
+ int rc;
+
+ for (i = 0; i < info->ocon_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ l = NULL;
+ for (j = 0; j < nel; j++) {
+ c = calloc(1, sizeof(ocontext_t));
+ if (!c)
+ return -1;
+ if (l)
+ l->next = c;
+ else
+ p->ocontexts[i] = c;
+ l = c;
+ switch (i) {
+ case OCON_XEN_ISID:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->sid[0] = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_PIRQ:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->u.pirq = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_IOPORT:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.ioport.low_ioport = le32_to_cpu(buf[0]);
+ c->u.ioport.high_ioport = le32_to_cpu(buf[1]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_IOMEM:
+ if (p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE) {
+ uint64_t b64[2];
+ rc = next_entry(b64, fp, sizeof(uint64_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.iomem.low_iomem = le64_to_cpu(b64[0]);
+ c->u.iomem.high_iomem = le64_to_cpu(b64[1]);
+ } else {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.iomem.low_iomem = le32_to_cpu(buf[0]);
+ c->u.iomem.high_iomem = le32_to_cpu(buf[1]);
+ }
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->u.device = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_XEN_DEVICETREE:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ len = le32_to_cpu(buf[0]);
+ c->u.name = malloc(len + 1);
+ if (!c->u.name)
+ return -1;
+ rc = next_entry(c->u.name, fp, len);
+ if (rc < 0)
+ return -1;
+ c->u.name[len] = 0;
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ default:
+ /* should never get here */
+ ERR(fp->handle, "Unknown Xen ocontext");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+static int ocontext_read_selinux(struct policydb_compat_info *info,
+ policydb_t * p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, len;
+ ocontext_t *l, *c;
+ uint32_t buf[8];
+ int rc;
+
+ for (i = 0; i < info->ocon_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ l = NULL;
+ for (j = 0; j < nel; j++) {
+ c = calloc(1, sizeof(ocontext_t));
+ if (!c) {
+ return -1;
+ }
+ if (l) {
+ l->next = c;
+ } else {
+ p->ocontexts[i] = c;
+ }
+ l = c;
+ switch (i) {
+ case OCON_ISID:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ c->sid[0] = le32_to_cpu(buf[0]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_FS:
+ case OCON_NETIF:
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ len = le32_to_cpu(buf[0]);
+ c->u.name = malloc(len + 1);
+ if (!c->u.name)
+ return -1;
+ rc = next_entry(c->u.name, fp, len);
+ if (rc < 0)
+ return -1;
+ c->u.name[len] = 0;
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ if (context_read_and_validate
+ (&c->context[1], p, fp))
+ return -1;
+ break;
+ case OCON_PORT:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ return -1;
+ c->u.port.protocol = le32_to_cpu(buf[0]);
+ c->u.port.low_port = le32_to_cpu(buf[1]);
+ c->u.port.high_port = le32_to_cpu(buf[2]);
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_NODE:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->u.node.addr = buf[0]; /* network order */
+ c->u.node.mask = buf[1]; /* network order */
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_FSUSE:
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ c->v.behavior = le32_to_cpu(buf[0]);
+ len = le32_to_cpu(buf[1]);
+ c->u.name = malloc(len + 1);
+ if (!c->u.name)
+ return -1;
+ rc = next_entry(c->u.name, fp, len);
+ if (rc < 0)
+ return -1;
+ c->u.name[len] = 0;
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ case OCON_NODE6:{
+ int k;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 8);
+ if (rc < 0)
+ return -1;
+ for (k = 0; k < 4; k++)
+ /* network order */
+ c->u.node6.addr[k] = buf[k];
+ for (k = 0; k < 4; k++)
+ /* network order */
+ c->u.node6.mask[k] = buf[k + 4];
+ if (context_read_and_validate
+ (&c->context[0], p, fp))
+ return -1;
+ break;
+ }
+ default:{
+ ERR(fp->handle, "Unknown SELinux ocontext");
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocontext_read(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ int rc = -1;
+ switch (p->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_read_selinux(info, p, fp);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_read_xen(info, p, fp);
+ break;
+ default:
+ ERR(fp->handle, "Unknown target");
+ }
+ return rc;
+}
+
+static int genfs_read(policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ size_t nel, nel2, len, len2;
+ genfs_t *genfs_p, *newgenfs, *genfs;
+ unsigned int i, j;
+ ocontext_t *l, *c, *newc = NULL;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ genfs_p = NULL;
+ for (i = 0; i < nel; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+ newgenfs = calloc(1, sizeof(genfs_t));
+ if (!newgenfs)
+ goto bad;
+ newgenfs->fstype = malloc(len + 1);
+ if (!newgenfs->fstype) {
+ free(newgenfs);
+ goto bad;
+ }
+ rc = next_entry(newgenfs->fstype, fp, len);
+ if (rc < 0) {
+ free(newgenfs->fstype);
+ free(newgenfs);
+ goto bad;
+ }
+ newgenfs->fstype[len] = 0;
+ for (genfs_p = NULL, genfs = p->genfs; genfs;
+ genfs_p = genfs, genfs = genfs->next) {
+ if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+ ERR(fp->handle, "dup genfs fstype %s",
+ newgenfs->fstype);
+ free(newgenfs->fstype);
+ free(newgenfs);
+ goto bad;
+ }
+ if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+ break;
+ }
+ newgenfs->next = genfs;
+ if (genfs_p)
+ genfs_p->next = newgenfs;
+ else
+ p->genfs = newgenfs;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ nel2 = le32_to_cpu(buf[0]);
+ for (j = 0; j < nel2; j++) {
+ newc = calloc(1, sizeof(ocontext_t));
+ if (!newc) {
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+ newc->u.name = malloc(len + 1);
+ if (!newc->u.name) {
+ goto bad;
+ }
+ rc = next_entry(newc->u.name, fp, len);
+ if (rc < 0)
+ goto bad;
+ newc->u.name[len] = 0;
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ newc->v.sclass = le32_to_cpu(buf[0]);
+ if (context_read_and_validate(&newc->context[0], p, fp))
+ goto bad;
+ for (l = NULL, c = newgenfs->head; c;
+ l = c, c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name) &&
+ (!c->v.sclass || !newc->v.sclass ||
+ newc->v.sclass == c->v.sclass)) {
+ ERR(fp->handle, "dup genfs entry "
+ "(%s,%s)", newgenfs->fstype,
+ c->u.name);
+ goto bad;
+ }
+ len = strlen(newc->u.name);
+ len2 = strlen(c->u.name);
+ if (len > len2)
+ break;
+ }
+ newc->next = c;
+ if (l)
+ l->next = newc;
+ else
+ newgenfs->head = newc;
+ }
+ }
+
+ return 0;
+
+ bad:
+ if (newc) {
+ context_destroy(&newc->context[0]);
+ context_destroy(&newc->context[1]);
+ free(newc->u.name);
+ free(newc);
+ }
+ return -1;
+}
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(mls_level_t * lp, struct policy_file *fp)
+{
+ uint32_t buf[1];
+ int rc;
+
+ mls_level_init(lp);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ ERR(fp->handle, "truncated level");
+ goto bad;
+ }
+ lp->sens = le32_to_cpu(buf[0]);
+
+ if (ebitmap_read(&lp->cat, fp)) {
+ ERR(fp->handle, "error reading level categories");
+ goto bad;
+ }
+ return 0;
+
+ bad:
+ return -EINVAL;
+}
+
+static int user_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
+{
+ char *key = 0;
+ user_datum_t *usrdatum;
+ uint32_t buf[3];
+ size_t len;
+ int rc, to_read = 2;
+
+ usrdatum = calloc(1, sizeof(user_datum_t));
+ if (!usrdatum)
+ return -1;
+
+ if (policydb_has_boundary_feature(p))
+ to_read = 3;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ usrdatum->s.value = le32_to_cpu(buf[1]);
+ if (policydb_has_boundary_feature(p))
+ usrdatum->bounds = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&usrdatum->roles.roles, fp))
+ goto bad;
+ } else {
+ if (role_set_read(&usrdatum->roles, fp))
+ goto bad;
+ }
+
+ /* users were not allowed in mls modules before version
+ * MOD_POLICYDB_VERSION_MLS_USERS, but they could have been
+ * required - the mls fields will be empty. user declarations in
+ * non-mls modules will also have empty mls fields */
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_MOD
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)) {
+ if (mls_read_range_helper(&usrdatum->exp_range, fp))
+ goto bad;
+ if (mls_read_level(&usrdatum->exp_dfltlevel, fp))
+ goto bad;
+ if (p->policy_type != POLICY_KERN) {
+ if (mls_range_to_semantic(&usrdatum->exp_range,
+ &usrdatum->range))
+ goto bad;
+ if (mls_level_to_semantic(&usrdatum->exp_dfltlevel,
+ &usrdatum->dfltlevel))
+ goto bad;
+ }
+ } else if ((p->policy_type == POLICY_MOD
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)) {
+ if (mls_read_semantic_range_helper(&usrdatum->range, fp))
+ goto bad;
+ if (mls_read_semantic_level_helper(&usrdatum->dfltlevel, fp))
+ goto bad;
+ }
+
+ if (hashtab_insert(h, key, usrdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ user_destroy(key, usrdatum, NULL);
+ return -1;
+}
+
+static int sens_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ level_datum_t *levdatum;
+ uint32_t buf[2], len;
+ int rc;
+
+ levdatum = malloc(sizeof(level_datum_t));
+ if (!levdatum)
+ return -1;
+ level_datum_init(levdatum);
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ levdatum->isalias = le32_to_cpu(buf[1]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ levdatum->level = malloc(sizeof(mls_level_t));
+ if (!levdatum->level || mls_read_level(levdatum->level, fp))
+ goto bad;
+
+ if (hashtab_insert(h, key, levdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ sens_destroy(key, levdatum, NULL);
+ return -1;
+}
+
+static int cat_read(policydb_t * p
+ __attribute__ ((unused)), hashtab_t h,
+ struct policy_file *fp)
+{
+ char *key = 0;
+ cat_datum_t *catdatum;
+ uint32_t buf[3], len;
+ int rc;
+
+ catdatum = malloc(sizeof(cat_datum_t));
+ if (!catdatum)
+ return -1;
+ cat_datum_init(catdatum);
+
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 3));
+ if (rc < 0)
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ catdatum->s.value = le32_to_cpu(buf[1]);
+ catdatum->isalias = le32_to_cpu(buf[2]);
+
+ key = malloc(len + 1);
+ if (!key)
+ goto bad;
+ rc = next_entry(key, fp, len);
+ if (rc < 0)
+ goto bad;
+ key[len] = 0;
+
+ if (hashtab_insert(h, key, catdatum))
+ goto bad;
+
+ return 0;
+
+ bad:
+ cat_destroy(key, catdatum, NULL);
+ return -1;
+}
+
+static int (*read_f[SYM_NUM]) (policydb_t * p, hashtab_t h,
+ struct policy_file * fp) = {
+common_read, class_read, role_read, type_read, user_read,
+ cond_read_bool, sens_read, cat_read,};
+
+/************** module reading functions below **************/
+
+static avrule_t *avrule_read(policydb_t * p
+ __attribute__ ((unused)), struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[2], len;
+ class_perm_node_t *cur, *tail = NULL;
+ avrule_t *avrule;
+ int rc;
+
+ avrule = (avrule_t *) malloc(sizeof(avrule_t));
+ if (!avrule)
+ return NULL;
+
+ avrule_init(avrule);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+
+ (avrule)->specified = le32_to_cpu(buf[0]);
+ (avrule)->flags = le32_to_cpu(buf[1]);
+
+ if (type_set_read(&avrule->stypes, fp))
+ goto bad;
+
+ if (type_set_read(&avrule->ttypes, fp))
+ goto bad;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ cur = (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+ if (!cur)
+ goto bad;
+ class_perm_node_init(cur);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0) {
+ free(cur);
+ goto bad;
+ }
+
+ cur->tclass = le32_to_cpu(buf[0]);
+ cur->data = le32_to_cpu(buf[1]);
+
+ if (!tail) {
+ avrule->perms = cur;
+ } else {
+ tail->next = cur;
+ }
+ tail = cur;
+ }
+
+ return avrule;
+ bad:
+ if (avrule) {
+ avrule_destroy(avrule);
+ free(avrule);
+ }
+ return NULL;
+}
+
+static int range_read(policydb_t * p, struct policy_file *fp)
+{
+ uint32_t buf[2], nel;
+ range_trans_t *rt, *lrt;
+ range_trans_rule_t *rtr, *lrtr = NULL;
+ unsigned int i;
+ int new_rangetr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lrt = NULL;
+ for (i = 0; i < nel; i++) {
+ rt = calloc(1, sizeof(range_trans_t));
+ if (!rt)
+ return -1;
+ if (lrt)
+ lrt->next = rt;
+ else
+ p->range_tr = rt;
+ rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
+ if (rc < 0)
+ return -1;
+ rt->source_type = le32_to_cpu(buf[0]);
+ rt->target_type = le32_to_cpu(buf[1]);
+ if (new_rangetr) {
+ rc = next_entry(buf, fp, (sizeof(uint32_t)));
+ if (rc < 0)
+ return -1;
+ rt->target_class = le32_to_cpu(buf[0]);
+ } else
+ rt->target_class = SECCLASS_PROCESS;
+ if (mls_read_range_helper(&rt->target_range, fp))
+ return -1;
+ lrt = rt;
+ }
+
+ /* if this is a kernel policy, we are done - otherwise we need to
+ * convert these structs to range_trans_rule_ts */
+ if (p->policy_type == POLICY_KERN)
+ return 0;
+
+ /* create range_trans_rules_ts that correspond to the range_trans_ts
+ * that were just read in from an older policy */
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ rtr = malloc(sizeof(range_trans_rule_t));
+ if (!rtr) {
+ return -1;
+ }
+ range_trans_rule_init(rtr);
+
+ if (lrtr)
+ lrtr->next = rtr;
+ else
+ p->global->enabled->range_tr_rules = rtr;
+
+ if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
+ return -1;
+
+ if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
+ return -1;
+
+ if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
+ return -1;
+
+ if (mls_range_to_semantic(&rt->target_range, &rtr->trange))
+ return -1;
+
+ lrtr = rtr;
+ }
+
+ /* now destroy the range_trans_ts */
+ lrt = NULL;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ lrt = rt;
+ }
+ if (lrt) {
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
+ free(lrt);
+ }
+ p->range_tr = NULL;
+
+ return 0;
+}
+
+int avrule_read_list(policydb_t * p, avrule_t ** avrules,
+ struct policy_file *fp)
+{
+ unsigned int i;
+ avrule_t *cur, *tail;
+ uint32_t buf[1], len;
+ int rc;
+
+ *avrules = tail = NULL;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ return -1;
+ }
+ len = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < len; i++) {
+ cur = avrule_read(p, fp);
+ if (!cur) {
+ return -1;
+ }
+
+ if (!tail) {
+ *avrules = cur;
+ } else {
+ tail->next = cur;
+ }
+ tail = cur;
+ }
+
+ return 0;
+}
+
+static int role_trans_rule_read(policydb_t *p, role_trans_rule_t ** r,
+ struct policy_file *fp)
+{
+ uint32_t buf[1], nel;
+ unsigned int i;
+ role_trans_rule_t *tr, *ltr;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ ltr = NULL;
+ for (i = 0; i < nel; i++) {
+ tr = malloc(sizeof(role_trans_rule_t));
+ if (!tr) {
+ return -1;
+ }
+ role_trans_rule_init(tr);
+
+ if (ltr) {
+ ltr->next = tr;
+ } else {
+ *r = tr;
+ }
+
+ if (role_set_read(&tr->roles, fp))
+ return -1;
+
+ if (type_set_read(&tr->types, fp))
+ return -1;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS) {
+ if (ebitmap_read(&tr->classes, fp))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(&tr->classes, SECCLASS_PROCESS - 1, 1))
+ return -1;
+ }
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ tr->new_role = le32_to_cpu(buf[0]);
+ ltr = tr;
+ }
+
+ return 0;
+}
+
+static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1], nel;
+ role_allow_rule_t *ra, *lra;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lra = NULL;
+ for (i = 0; i < nel; i++) {
+ ra = malloc(sizeof(role_allow_rule_t));
+ if (!ra) {
+ return -1;
+ }
+ role_allow_rule_init(ra);
+
+ if (lra) {
+ lra->next = ra;
+ } else {
+ *r = ra;
+ }
+
+ if (role_set_read(&ra->roles, fp))
+ return -1;
+
+ if (role_set_read(&ra->new_roles, fp))
+ return -1;
+
+ lra = ra;
+ }
+ return 0;
+}
+
+static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_file *fp)
+{
+ uint32_t buf[2], nel;
+ unsigned int i, len;
+ filename_trans_rule_t *ftr, *lftr;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ lftr = NULL;
+ for (i = 0; i < nel; i++) {
+ ftr = malloc(sizeof(*ftr));
+ if (!ftr)
+ return -1;
+
+ filename_trans_rule_init(ftr);
+
+ if (lftr)
+ lftr->next = ftr;
+ else
+ *r = ftr;
+ lftr = ftr;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ len = le32_to_cpu(buf[0]);
+
+ ftr->name = malloc(len + 1);
+ if (!ftr->name)
+ return -1;
+
+ rc = next_entry(ftr->name, fp, len);
+ if (rc)
+ return -1;
+ ftr->name[len] = 0;
+
+ if (type_set_read(&ftr->stypes, fp))
+ return -1;
+
+ if (type_set_read(&ftr->ttypes, fp))
+ return -1;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ ftr->tclass = le32_to_cpu(buf[0]);
+ ftr->otype = le32_to_cpu(buf[1]);
+ }
+
+ return 0;
+}
+
+static int range_trans_rule_read(range_trans_rule_t ** r,
+ struct policy_file *fp)
+{
+ uint32_t buf[1], nel;
+ unsigned int i;
+ range_trans_rule_t *rt, *lrt = NULL;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ nel = le32_to_cpu(buf[0]);
+ for (i = 0; i < nel; i++) {
+ rt = malloc(sizeof(range_trans_rule_t));
+ if (!rt) {
+ return -1;
+ }
+ range_trans_rule_init(rt);
+
+ if (lrt)
+ lrt->next = rt;
+ else
+ *r = rt;
+
+ if (type_set_read(&rt->stypes, fp))
+ return -1;
+
+ if (type_set_read(&rt->ttypes, fp))
+ return -1;
+
+ if (ebitmap_read(&rt->tclasses, fp))
+ return -1;
+
+ if (mls_read_semantic_range_helper(&rt->trange, fp))
+ return -1;
+
+ lrt = rt;
+ }
+
+ return 0;
+}
+
+static int scope_index_read(scope_index_t * scope_index,
+ unsigned int num_scope_syms, struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1];
+ int rc;
+
+ for (i = 0; i < num_scope_syms; i++) {
+ if (ebitmap_read(scope_index->scope + i, fp) == -1) {
+ return -1;
+ }
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ scope_index->class_perms_len = le32_to_cpu(buf[0]);
+ if (scope_index->class_perms_len == 0) {
+ scope_index->class_perms_map = NULL;
+ return 0;
+ }
+ if ((scope_index->class_perms_map =
+ calloc(scope_index->class_perms_len,
+ sizeof(*scope_index->class_perms_map))) == NULL) {
+ return -1;
+ }
+ for (i = 0; i < scope_index->class_perms_len; i++) {
+ if (ebitmap_read(scope_index->class_perms_map + i, fp) == -1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
+ unsigned int num_scope_syms, struct policy_file *fp)
+{
+ uint32_t buf[2], nprim, nel;
+ unsigned int i, j;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ decl->decl_id = le32_to_cpu(buf[0]);
+ decl->enabled = le32_to_cpu(buf[1]);
+ if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
+ avrule_read_list(p, &decl->avrules, fp) == -1 ||
+ role_trans_rule_read(p, &decl->role_tr_rules, fp) == -1 ||
+ role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
+ return -1;
+ }
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_rule_read(&decl->filename_trans_rules, fp))
+ return -1;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+ range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
+ return -1;
+ }
+ if (scope_index_read(&decl->required, num_scope_syms, fp) == -1 ||
+ scope_index_read(&decl->declared, num_scope_syms, fp) == -1) {
+ return -1;
+ }
+
+ for (i = 0; i < num_scope_syms; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return -1;
+ nprim = le32_to_cpu(buf[0]);
+ nel = le32_to_cpu(buf[1]);
+ for (j = 0; j < nel; j++) {
+ if (read_f[i] (p, decl->symtab[i].table, fp)) {
+ return -1;
+ }
+ }
+ decl->symtab[i].nprim = nprim;
+ }
+ return 0;
+}
+
+static int avrule_block_read(policydb_t * p,
+ avrule_block_t ** block,
+ unsigned int num_scope_syms,
+ struct policy_file *fp)
+{
+ avrule_block_t *last_block = NULL, *curblock;
+ uint32_t buf[1], num_blocks, nel;
+ int rc;
+
+ assert(*block == NULL);
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+ num_blocks = le32_to_cpu(buf[0]);
+ nel = num_blocks;
+ while (num_blocks > 0) {
+ avrule_decl_t *last_decl = NULL, *curdecl;
+ uint32_t num_decls;
+ if ((curblock = calloc(1, sizeof(*curblock))) == NULL) {
+ return -1;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0) {
+ free(curblock);
+ return -1;
+ }
+ /* if this is the first block its non-optional, else its optional */
+ if (num_blocks != nel)
+ curblock->flags |= AVRULE_OPTIONAL;
+
+ num_decls = le32_to_cpu(buf[0]);
+ while (num_decls > 0) {
+ if ((curdecl = avrule_decl_create(0)) == NULL) {
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ if (avrule_decl_read(p, curdecl, num_scope_syms, fp) ==
+ -1) {
+ avrule_decl_destroy(curdecl);
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ if (curdecl->enabled) {
+ if (curblock->enabled != NULL) {
+ /* probably a corrupt file */
+ avrule_decl_destroy(curdecl);
+ avrule_block_destroy(curblock);
+ return -1;
+ }
+ curblock->enabled = curdecl;
+ }
+ /* one must be careful to reconstruct the
+ * decl chain in its correct order */
+ if (curblock->branch_list == NULL) {
+ curblock->branch_list = curdecl;
+ } else {
+ assert(last_decl);
+ last_decl->next = curdecl;
+ }
+ last_decl = curdecl;
+ num_decls--;
+ }
+
+ if (*block == NULL) {
+ *block = curblock;
+ } else {
+ assert(last_block);
+ last_block->next = curblock;
+ }
+ last_block = curblock;
+
+ num_blocks--;
+ }
+
+ return 0;
+}
+
+static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
+{
+ scope_datum_t *scope = NULL;
+ uint32_t buf[2];
+ char *key = NULL;
+ size_t key_len;
+ unsigned int i;
+ hashtab_t h = p->scope[symnum].table;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto cleanup;
+ key_len = le32_to_cpu(buf[0]);
+ key = malloc(key_len + 1);
+ if (!key)
+ goto cleanup;
+ rc = next_entry(key, fp, key_len);
+ if (rc < 0)
+ goto cleanup;
+ key[key_len] = '\0';
+
+ /* ensure that there already exists a symbol with this key */
+ if (hashtab_search(p->symtab[symnum].table, key) == NULL) {
+ goto cleanup;
+ }
+
+ if ((scope = calloc(1, sizeof(*scope))) == NULL) {
+ goto cleanup;
+ }
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto cleanup;
+ scope->scope = le32_to_cpu(buf[0]);
+ scope->decl_ids_len = le32_to_cpu(buf[1]);
+ assert(scope->decl_ids_len > 0);
+ if ((scope->decl_ids =
+ malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) {
+ goto cleanup;
+ }
+ rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len);
+ if (rc < 0)
+ goto cleanup;
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ scope->decl_ids[i] = le32_to_cpu(scope->decl_ids[i]);
+ }
+
+ if (strcmp(key, "object_r") == 0 && h == p->p_roles_scope.table) {
+ /* object_r was already added to this table in roles_init() */
+ scope_destroy(key, scope, NULL);
+ } else {
+ if (hashtab_insert(h, key, scope)) {
+ goto cleanup;
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ scope_destroy(key, scope, NULL);
+ return -1;
+}
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
+{
+
+ unsigned int i, j, r_policyvers;
+ uint32_t buf[5];
+ size_t len, nprim, nel;
+ char *policydb_str;
+ struct policydb_compat_info *info;
+ unsigned int policy_type, bufindex;
+ ebitmap_node_t *tnode;
+ int rc;
+
+ /* Read the magic number and string length. */
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ return POLICYDB_ERROR;
+ for (i = 0; i < 2; i++)
+ buf[i] = le32_to_cpu(buf[i]);
+
+ if (buf[0] == POLICYDB_MAGIC) {
+ policy_type = POLICY_KERN;
+ } else if (buf[0] == POLICYDB_MOD_MAGIC) {
+ policy_type = POLICY_MOD;
+ } else {
+ ERR(fp->handle, "policydb magic number %#08x does not "
+ "match expected magic number %#08x or %#08x",
+ buf[0], POLICYDB_MAGIC, POLICYDB_MOD_MAGIC);
+ return POLICYDB_ERROR;
+ }
+
+ len = buf[1];
+ if (len > POLICYDB_STRING_MAX_LENGTH) {
+ ERR(fp->handle, "policydb string length too long ");
+ return POLICYDB_ERROR;
+ }
+
+ policydb_str = malloc(len + 1);
+ if (!policydb_str) {
+ ERR(fp->handle, "unable to allocate memory for policydb "
+ "string of length %zu", len);
+ return POLICYDB_ERROR;
+ }
+ rc = next_entry(policydb_str, fp, len);
+ if (rc < 0) {
+ ERR(fp->handle, "truncated policydb string identifier");
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ policydb_str[len] = 0;
+
+ if (policy_type == POLICY_KERN) {
+ for (i = 0; i < POLICYDB_TARGET_SZ; i++) {
+ if ((strcmp(policydb_str, policydb_target_strings[i])
+ == 0)) {
+ policydb_set_target_platform(p, i);
+ break;
+ }
+ }
+
+ if (i == POLICYDB_TARGET_SZ) {
+ ERR(fp->handle, "cannot find a valid target for policy "
+ "string %s", policydb_str);
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ } else {
+ if (strcmp(policydb_str, POLICYDB_MOD_STRING)) {
+ ERR(fp->handle, "invalid string identifier %s",
+ policydb_str);
+ free(policydb_str);
+ return POLICYDB_ERROR;
+ }
+ }
+
+ /* Done with policydb_str. */
+ free(policydb_str);
+ policydb_str = NULL;
+
+ /* Read the version, config, and table sizes (and policy type if it's a module). */
+ if (policy_type == POLICY_KERN)
+ nel = 4;
+ else
+ nel = 5;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t) * nel);
+ if (rc < 0)
+ return POLICYDB_ERROR;
+ for (i = 0; i < nel; i++)
+ buf[i] = le32_to_cpu(buf[i]);
+
+ bufindex = 0;
+
+ if (policy_type == POLICY_MOD) {
+ /* We know it's a module but not whether it's a base
+ module or regular binary policy module. buf[0]
+ tells us which. */
+ policy_type = buf[bufindex];
+ if (policy_type != POLICY_MOD && policy_type != POLICY_BASE) {
+ ERR(fp->handle, "unknown module type: %#08x",
+ policy_type);
+ return POLICYDB_ERROR;
+ }
+ bufindex++;
+ }
+
+ r_policyvers = buf[bufindex];
+ if (policy_type == POLICY_KERN) {
+ if (r_policyvers < POLICYDB_VERSION_MIN ||
+ r_policyvers > POLICYDB_VERSION_MAX) {
+ ERR(fp->handle, "policydb version %d does not match "
+ "my version range %d-%d", buf[bufindex],
+ POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+ return POLICYDB_ERROR;
+ }
+ } else if (policy_type == POLICY_BASE || policy_type == POLICY_MOD) {
+ if (r_policyvers < MOD_POLICYDB_VERSION_MIN ||
+ r_policyvers > MOD_POLICYDB_VERSION_MAX) {
+ ERR(fp->handle, "policydb module version %d does "
+ "not match my version range %d-%d",
+ buf[bufindex], MOD_POLICYDB_VERSION_MIN,
+ MOD_POLICYDB_VERSION_MAX);
+ return POLICYDB_ERROR;
+ }
+ } else {
+ assert(0);
+ }
+ bufindex++;
+
+ /* Set the policy type and version from the read values. */
+ p->policy_type = policy_type;
+ p->policyvers = r_policyvers;
+
+ if (buf[bufindex] & POLICYDB_CONFIG_MLS) {
+ p->mls = 1;
+ } else {
+ p->mls = 0;
+ }
+
+ p->handle_unknown = buf[bufindex] & POLICYDB_CONFIG_UNKNOWN_MASK;
+
+ bufindex++;
+
+ info = policydb_lookup_compat(r_policyvers, policy_type,
+ p->target_platform);
+ if (!info) {
+ ERR(fp->handle, "unable to find policy compat info "
+ "for version %d", r_policyvers);
+ goto bad;
+ }
+
+ if (buf[bufindex] != info->sym_num
+ || buf[bufindex + 1] != info->ocon_num) {
+ ERR(fp->handle,
+ "policydb table sizes (%d,%d) do not " "match mine (%d,%d)",
+ buf[bufindex], buf[bufindex + 1], info->sym_num,
+ info->ocon_num);
+ goto bad;
+ }
+
+ if (p->policy_type == POLICY_MOD) {
+ /* Get the module name and version */
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ len = le32_to_cpu(buf[0]);
+ if ((p->name = malloc(len + 1)) == NULL) {
+ goto bad;
+ }
+ if ((rc = next_entry(p->name, fp, len)) < 0) {
+ goto bad;
+ }
+ p->name[len] = '\0';
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ len = le32_to_cpu(buf[0]);
+ if ((p->version = malloc(len + 1)) == NULL) {
+ goto bad;
+ }
+ if ((rc = next_entry(p->version, fp, len)) < 0) {
+ goto bad;
+ }
+ p->version[len] = '\0';
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_MOD)) {
+ if (ebitmap_read(&p->policycaps, fp))
+ goto bad;
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ if (ebitmap_read(&p->permissive_map, fp))
+ goto bad;
+ }
+
+ for (i = 0; i < info->sym_num; i++) {
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+ if (rc < 0)
+ goto bad;
+ nprim = le32_to_cpu(buf[0]);
+ nel = le32_to_cpu(buf[1]);
+ for (j = 0; j < nel; j++) {
+ if (read_f[i] (p, p->symtab[i].table, fp))
+ goto bad;
+ }
+
+ p->symtab[i].nprim = nprim;
+ }
+
+ if (policy_type == POLICY_KERN) {
+ if (avtab_read(&p->te_avtab, fp, r_policyvers))
+ goto bad;
+ if (r_policyvers >= POLICYDB_VERSION_BOOL)
+ if (cond_read_list(p, &p->cond_list, fp))
+ goto bad;
+ if (role_trans_read(p, fp))
+ goto bad;
+ if (role_allow_read(&p->role_allow, fp))
+ goto bad;
+ if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_read(&p->filename_trans, fp))
+ goto bad;
+ } else {
+ /* first read the AV rule blocks, then the scope tables */
+ avrule_block_destroy(p->global);
+ p->global = NULL;
+ if (avrule_block_read(p, &p->global, info->sym_num, fp) == -1) {
+ goto bad;
+ }
+ for (i = 0; i < info->sym_num; i++) {
+ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) {
+ goto bad;
+ }
+ nel = le32_to_cpu(buf[0]);
+ for (j = 0; j < nel; j++) {
+ if (scope_read(p, i, fp))
+ goto bad;
+ }
+ }
+
+ }
+
+ if (policydb_index_decls(p))
+ goto bad;
+
+ if (policydb_index_classes(p))
+ goto bad;
+
+ if (policydb_index_others(fp->handle, p, verbose))
+ goto bad;
+
+ if (ocontext_read(info, p, fp) == -1) {
+ goto bad;
+ }
+
+ if (genfs_read(p, fp) == -1) {
+ goto bad;
+ }
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_MLS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS)) {
+ if (range_read(p, fp)) {
+ goto bad;
+ }
+ }
+
+ if (policy_type == POLICY_KERN) {
+ p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+ p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+ if (!p->type_attr_map || !p->attr_type_map)
+ goto bad;
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_init(&p->type_attr_map[i]);
+ ebitmap_init(&p->attr_type_map[i]);
+ }
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (r_policyvers >= POLICYDB_VERSION_AVTAB) {
+ if (ebitmap_read(&p->type_attr_map[i], fp))
+ goto bad;
+ ebitmap_for_each_bit(&p->type_attr_map[i],
+ tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j)
+ || i == j)
+ continue;
+ if (ebitmap_set_bit
+ (&p->attr_type_map[j], i, 1))
+ goto bad;
+ }
+ }
+ /* add the type itself as the degenerate case */
+ if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+ goto bad;
+ if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
+ if (ebitmap_set_bit(&p->attr_type_map[i], i, 1))
+ goto bad;
+ }
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+ bad:
+ return POLICYDB_ERROR;
+}
+
+int policydb_reindex_users(policydb_t * p)
+{
+ unsigned int i = SYM_USERS;
+
+ if (p->user_val_to_struct)
+ free(p->user_val_to_struct);
+ if (p->sym_val_to_name[i])
+ free(p->sym_val_to_name[i]);
+
+ p->user_val_to_struct = (user_datum_t **)
+ malloc(p->p_users.nprim * sizeof(user_datum_t *));
+ if (!p->user_val_to_struct)
+ return -1;
+
+ p->sym_val_to_name[i] = (char **)
+ malloc(p->symtab[i].nprim * sizeof(char *));
+ if (!p->sym_val_to_name[i])
+ return -1;
+
+ if (hashtab_map(p->symtab[i].table, index_f[i], p))
+ return -1;
+
+ /* Expand user roles for context validity checking */
+ if (hashtab_map(p->p_users.table, policydb_user_cache, p))
+ return -1;
+
+ return 0;
+}
+
+void policy_file_init(policy_file_t *pf)
+{
+ memset(pf, 0, sizeof(policy_file_t));
+}
+
+int policydb_set_target_platform(policydb_t *p, int platform)
+{
+ if (platform == SEPOL_TARGET_SELINUX)
+ p->target_platform = SEPOL_TARGET_SELINUX;
+ else if (platform == SEPOL_TARGET_XEN)
+ p->target_platform = SEPOL_TARGET_XEN;
+ else
+ return -1;
+
+ return 0;
+}
+
diff --git a/libsepol/src/policydb_convert.c b/libsepol/src/policydb_convert.c
new file mode 100644
index 0000000..3fc40cb
--- /dev/null
+++ b/libsepol/src/policydb_convert.c
@@ -0,0 +1,101 @@
+#include <stdlib.h>
+
+#include "private.h"
+#include "debug.h"
+
+#include <sepol/policydb/policydb.h>
+
+/* Construct a policydb from the supplied (data, len) pair */
+
+int policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, policydb_t * policydb)
+{
+
+ policy_file_t pf;
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = data;
+ pf.len = len;
+ pf.handle = handle;
+
+ if (policydb_read(policydb, &pf, 0)) {
+ policydb_destroy(policydb);
+ ERR(handle, "policy image is invalid");
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* Write a policydb to a memory region, and return the (data, len) pair. */
+
+int policydb_to_image(sepol_handle_t * handle,
+ policydb_t * policydb, void **newdata, size_t * newlen)
+{
+
+ void *tmp_data = NULL;
+ size_t tmp_len;
+ policy_file_t pf;
+ struct policydb tmp_policydb;
+
+ /* Compute the length for the new policy image. */
+ policy_file_init(&pf);
+ pf.type = PF_LEN;
+ pf.handle = handle;
+ if (policydb_write(policydb, &pf)) {
+ ERR(handle, "could not compute policy length");
+ errno = EINVAL;
+ goto err;
+ }
+
+ /* Allocate the new policy image. */
+ pf.type = PF_USE_MEMORY;
+ pf.data = malloc(pf.len);
+ if (!pf.data) {
+ ERR(handle, "out of memory");
+ goto err;
+ }
+
+ /* Need to save len and data prior to modification by policydb_write. */
+ tmp_len = pf.len;
+ tmp_data = pf.data;
+
+ /* Write out the new policy image. */
+ if (policydb_write(policydb, &pf)) {
+ ERR(handle, "could not write policy");
+ errno = EINVAL;
+ goto err;
+ }
+
+ /* Verify the new policy image. */
+ pf.type = PF_USE_MEMORY;
+ pf.data = tmp_data;
+ pf.len = tmp_len;
+ if (policydb_init(&tmp_policydb)) {
+ ERR(handle, "Out of memory");
+ errno = ENOMEM;
+ goto err;
+ }
+ if (policydb_read(&tmp_policydb, &pf, 0)) {
+ ERR(handle, "new policy image is invalid");
+ errno = EINVAL;
+ goto err;
+ }
+ policydb_destroy(&tmp_policydb);
+
+ /* Update (newdata, newlen) */
+ *newdata = tmp_data;
+ *newlen = tmp_len;
+
+ /* Recover */
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not create policy image");
+
+ /* Recover */
+ free(tmp_data);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/policydb_internal.h b/libsepol/src/policydb_internal.h
new file mode 100644
index 0000000..f7bcdfa
--- /dev/null
+++ b/libsepol/src/policydb_internal.h
@@ -0,0 +1,10 @@
+#ifndef _SEPOL_POLICYDB_INTERNAL_H_
+#define _SEPOL_POLICYDB_INTERNAL_H_
+
+#include <sepol/policydb.h>
+#include "dso.h"
+
+hidden_proto(sepol_policydb_create)
+ hidden_proto(sepol_policydb_free)
+extern const char *policydb_target_strings[];
+#endif
diff --git a/libsepol/src/policydb_public.c b/libsepol/src/policydb_public.c
new file mode 100644
index 0000000..e721842
--- /dev/null
+++ b/libsepol/src/policydb_public.c
@@ -0,0 +1,210 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include <sepol/policydb/policydb.h>
+#include "policydb_internal.h"
+
+/* Policy file interfaces. */
+
+int sepol_policy_file_create(sepol_policy_file_t ** pf)
+{
+ *pf = calloc(1, sizeof(sepol_policy_file_t));
+ if (!(*pf))
+ return -1;
+ return 0;
+}
+
+void sepol_policy_file_set_mem(sepol_policy_file_t * spf,
+ char *data, size_t len)
+{
+ struct policy_file *pf = &spf->pf;
+ if (!len) {
+ pf->type = PF_LEN;
+ return;
+ }
+ pf->type = PF_USE_MEMORY;
+ pf->data = data;
+ pf->len = len;
+ pf->size = len;
+ return;
+}
+
+void sepol_policy_file_set_fp(sepol_policy_file_t * spf, FILE * fp)
+{
+ struct policy_file *pf = &spf->pf;
+ pf->type = PF_USE_STDIO;
+ pf->fp = fp;
+ return;
+}
+
+int sepol_policy_file_get_len(sepol_policy_file_t * spf, size_t * len)
+{
+ struct policy_file *pf = &spf->pf;
+ if (pf->type != PF_LEN)
+ return -1;
+ *len = pf->len;
+ return 0;
+}
+
+void sepol_policy_file_set_handle(sepol_policy_file_t * pf,
+ sepol_handle_t * handle)
+{
+ pf->pf.handle = handle;
+}
+
+void sepol_policy_file_free(sepol_policy_file_t * pf)
+{
+ free(pf);
+}
+
+/* Policydb interfaces. */
+
+int sepol_policydb_create(sepol_policydb_t ** sp)
+{
+ policydb_t *p;
+ *sp = malloc(sizeof(sepol_policydb_t));
+ if (!(*sp))
+ return -1;
+ p = &(*sp)->p;
+ if (policydb_init(p)) {
+ free(*sp);
+ return -1;
+ }
+ return 0;
+}
+
+hidden_def(sepol_policydb_create)
+
+void sepol_policydb_free(sepol_policydb_t * p)
+{
+ if (!p)
+ return;
+ policydb_destroy(&p->p);
+ free(p);
+}
+
+hidden_def(sepol_policydb_free)
+
+int sepol_policy_kern_vers_min(void)
+{
+ return POLICYDB_VERSION_MIN;
+}
+
+int sepol_policy_kern_vers_max(void)
+{
+ return POLICYDB_VERSION_MAX;
+}
+
+int sepol_policydb_set_typevers(sepol_policydb_t * sp, unsigned int type)
+{
+ struct policydb *p = &sp->p;
+ switch (type) {
+ case POLICY_KERN:
+ p->policyvers = POLICYDB_VERSION_MAX;
+ break;
+ case POLICY_BASE:
+ case POLICY_MOD:
+ p->policyvers = MOD_POLICYDB_VERSION_MAX;
+ break;
+ default:
+ return -1;
+ }
+ p->policy_type = type;
+ return 0;
+}
+
+int sepol_policydb_set_vers(sepol_policydb_t * sp, unsigned int vers)
+{
+ struct policydb *p = &sp->p;
+ switch (p->policy_type) {
+ case POLICY_KERN:
+ if (vers < POLICYDB_VERSION_MIN || vers > POLICYDB_VERSION_MAX)
+ return -1;
+ break;
+ case POLICY_BASE:
+ case POLICY_MOD:
+ if (vers < MOD_POLICYDB_VERSION_MIN
+ || vers > MOD_POLICYDB_VERSION_MAX)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ p->policyvers = vers;
+ return 0;
+}
+
+int sepol_policydb_set_handle_unknown(sepol_policydb_t * sp,
+ unsigned int handle_unknown)
+{
+ struct policydb *p = &sp->p;
+
+ switch (handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ case SEPOL_REJECT_UNKNOWN:
+ case SEPOL_ALLOW_UNKNOWN:
+ break;
+ default:
+ return -1;
+ }
+
+ p->handle_unknown = handle_unknown;
+ return 0;
+}
+
+int sepol_policydb_set_target_platform(sepol_policydb_t * sp,
+ int target_platform)
+{
+ struct policydb *p = &sp->p;
+
+ switch (target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ case SEPOL_TARGET_XEN:
+ break;
+ default:
+ return -1;
+ }
+
+ p->target_platform = target_platform;
+ return 0;
+}
+
+int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+ return policydb_read(&p->p, &pf->pf, 0);
+}
+
+int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf)
+{
+ return policydb_write(&p->p, &pf->pf);
+}
+
+int sepol_policydb_from_image(sepol_handle_t * handle,
+ void *data, size_t len, sepol_policydb_t * p)
+{
+ return policydb_from_image(handle, data, len, &p->p);
+}
+
+int sepol_policydb_to_image(sepol_handle_t * handle,
+ sepol_policydb_t * p, void **newdata,
+ size_t * newlen)
+{
+ return policydb_to_image(handle, &p->p, newdata, newlen);
+}
+
+int sepol_policydb_mls_enabled(const sepol_policydb_t * p)
+{
+
+ return p->p.mls;
+}
+
+/*
+ * Enable compatibility mode for SELinux network checks iff
+ * the packet class is not defined in the policy.
+ */
+#define PACKET_CLASS_NAME "packet"
+int sepol_policydb_compat_net(const sepol_policydb_t * p)
+{
+ return (hashtab_search(p->p.p_classes.table, PACKET_CLASS_NAME) ==
+ NULL);
+}
diff --git a/libsepol/src/port_internal.h b/libsepol/src/port_internal.h
new file mode 100644
index 0000000..ffb5f65
--- /dev/null
+++ b/libsepol/src/port_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_PORT_INTERNAL_H_
+#define _SEPOL_PORT_INTERNAL_H_
+
+#include <sepol/port_record.h>
+#include <sepol/ports.h>
+#include "dso.h"
+
+hidden_proto(sepol_port_create)
+ hidden_proto(sepol_port_free)
+ hidden_proto(sepol_port_get_con)
+ hidden_proto(sepol_port_get_high)
+ hidden_proto(sepol_port_get_low)
+ hidden_proto(sepol_port_get_proto)
+ hidden_proto(sepol_port_get_proto_str)
+ hidden_proto(sepol_port_key_create)
+ hidden_proto(sepol_port_key_unpack)
+ hidden_proto(sepol_port_set_con)
+ hidden_proto(sepol_port_set_proto)
+ hidden_proto(sepol_port_set_range)
+#endif
diff --git a/libsepol/src/port_record.c b/libsepol/src/port_record.c
new file mode 100644
index 0000000..ed9093b
--- /dev/null
+++ b/libsepol/src/port_record.c
@@ -0,0 +1,290 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_port {
+ /* Low - High range. Same for single ports. */
+ int low, high;
+
+ /* Protocol */
+ int proto;
+
+ /* Context */
+ sepol_context_t *con;
+};
+
+struct sepol_port_key {
+ /* Low - High range. Same for single ports. */
+ int low, high;
+
+ /* Protocol */
+ int proto;
+};
+
+/* Key */
+int sepol_port_key_create(sepol_handle_t * handle,
+ int low, int high, int proto,
+ sepol_port_key_t ** key_ptr)
+{
+
+ sepol_port_key_t *tmp_key =
+ (sepol_port_key_t *) malloc(sizeof(sepol_port_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, could not create " "port key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->low = low;
+ tmp_key->high = high;
+ tmp_key->proto = proto;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_key_create)
+
+void sepol_port_key_unpack(const sepol_port_key_t * key,
+ int *low, int *high, int *proto)
+{
+
+ *low = key->low;
+ *high = key->high;
+ *proto = key->proto;
+}
+
+hidden_def(sepol_port_key_unpack)
+
+int sepol_port_key_extract(sepol_handle_t * handle,
+ const sepol_port_t * port,
+ sepol_port_key_t ** key_ptr)
+{
+
+ if (sepol_port_key_create
+ (handle, port->low, port->high, port->proto, key_ptr) < 0) {
+
+ ERR(handle, "could not extract key from port %s %d:%d",
+ sepol_port_get_proto_str(port->proto),
+ port->low, port->high);
+
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_port_key_free(sepol_port_key_t * key)
+{
+ free(key);
+}
+
+int sepol_port_compare(const sepol_port_t * port, const sepol_port_key_t * key)
+{
+
+ if ((port->low == key->low) &&
+ (port->high == key->high) && (port->proto == key->proto))
+ return 0;
+
+ if (port->low < key->low)
+ return -1;
+
+ else if (key->low < port->low)
+ return 1;
+
+ else if (port->high < key->high)
+ return -1;
+
+ else if (key->high < port->high)
+ return 1;
+
+ else if (port->proto < key->proto)
+ return -1;
+
+ else
+ return 1;
+}
+
+int sepol_port_compare2(const sepol_port_t * port, const sepol_port_t * port2)
+{
+
+ if ((port->low == port2->low) &&
+ (port->high == port2->high) && (port->proto == port2->proto))
+ return 0;
+
+ if (port->low < port2->low)
+ return -1;
+
+ else if (port2->low < port->low)
+ return 1;
+
+ else if (port->high < port2->high)
+ return -1;
+
+ else if (port2->high < port->high)
+ return 1;
+
+ else if (port->proto < port2->proto)
+ return -1;
+
+ else
+ return 1;
+}
+
+/* Port */
+int sepol_port_get_low(const sepol_port_t * port)
+{
+
+ return port->low;
+}
+
+hidden_def(sepol_port_get_low)
+
+int sepol_port_get_high(const sepol_port_t * port)
+{
+
+ return port->high;
+}
+
+hidden_def(sepol_port_get_high)
+
+void sepol_port_set_port(sepol_port_t * port, int port_num)
+{
+
+ port->low = port_num;
+ port->high = port_num;
+}
+
+void sepol_port_set_range(sepol_port_t * port, int low, int high)
+{
+
+ port->low = low;
+ port->high = high;
+}
+
+hidden_def(sepol_port_set_range)
+
+/* Protocol */
+int sepol_port_get_proto(const sepol_port_t * port)
+{
+
+ return port->proto;
+}
+
+hidden_def(sepol_port_get_proto)
+
+const char *sepol_port_get_proto_str(int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_UDP:
+ return "udp";
+ case SEPOL_PROTO_TCP:
+ return "tcp";
+ case SEPOL_PROTO_DCCP:
+ return "dccp";
+ default:
+ return "???";
+ }
+}
+
+hidden_def(sepol_port_get_proto_str)
+
+void sepol_port_set_proto(sepol_port_t * port, int proto)
+{
+
+ port->proto = proto;
+}
+
+hidden_def(sepol_port_set_proto)
+
+/* Create */
+int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port)
+{
+
+ sepol_port_t *tmp_port = (sepol_port_t *) malloc(sizeof(sepol_port_t));
+
+ if (!tmp_port) {
+ ERR(handle, "out of memory, could not create " "port record");
+ return STATUS_ERR;
+ }
+
+ tmp_port->low = 0;
+ tmp_port->high = 0;
+ tmp_port->proto = SEPOL_PROTO_UDP;
+ tmp_port->con = NULL;
+ *port = tmp_port;
+
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_create)
+
+/* Deep copy clone */
+int sepol_port_clone(sepol_handle_t * handle,
+ const sepol_port_t * port, sepol_port_t ** port_ptr)
+{
+
+ sepol_port_t *new_port = NULL;
+ if (sepol_port_create(handle, &new_port) < 0)
+ goto err;
+
+ new_port->low = port->low;
+ new_port->high = port->high;
+ new_port->proto = port->proto;
+
+ if (port->con &&
+ (sepol_context_clone(handle, port->con, &new_port->con) < 0))
+ goto err;
+
+ *port_ptr = new_port;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone port record");
+ sepol_port_free(new_port);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_port_free(sepol_port_t * port)
+{
+
+ if (!port)
+ return;
+
+ sepol_context_free(port->con);
+ free(port);
+}
+
+hidden_def(sepol_port_free)
+
+/* Context */
+sepol_context_t *sepol_port_get_con(const sepol_port_t * port)
+{
+
+ return port->con;
+}
+
+hidden_def(sepol_port_get_con)
+
+int sepol_port_set_con(sepol_handle_t * handle,
+ sepol_port_t * port, sepol_context_t * con)
+{
+
+ sepol_context_t *newcon;
+
+ if (sepol_context_clone(handle, con, &newcon) < 0) {
+ ERR(handle, "out of memory, could not set port context");
+ return STATUS_ERR;
+ }
+
+ sepol_context_free(port->con);
+ port->con = newcon;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_port_set_con)
diff --git a/libsepol/src/ports.c b/libsepol/src/ports.c
new file mode 100644
index 0000000..62ec602
--- /dev/null
+++ b/libsepol/src/ports.c
@@ -0,0 +1,318 @@
+#include <netinet/in.h>
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "port_internal.h"
+
+static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
+{
+
+ switch (proto) {
+ case SEPOL_PROTO_TCP:
+ return IPPROTO_TCP;
+ case SEPOL_PROTO_UDP:
+ return IPPROTO_UDP;
+ case SEPOL_PROTO_DCCP:
+ return IPPROTO_DCCP;
+ default:
+ ERR(handle, "unsupported protocol %u", proto);
+ return STATUS_ERR;
+ }
+}
+
+static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
+{
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ return SEPOL_PROTO_TCP;
+ case IPPROTO_UDP:
+ return SEPOL_PROTO_UDP;
+ case IPPROTO_DCCP:
+ return SEPOL_PROTO_DCCP;
+ default:
+ ERR(handle, "invalid protocol %u " "found in policy", proto);
+ return STATUS_ERR;
+ }
+}
+
+/* Create a low level port structure from
+ * a high level representation */
+static int port_from_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t ** port, const sepol_port_t * data)
+{
+
+ ocontext_t *tmp_port = NULL;
+ context_struct_t *tmp_con = NULL;
+ int tmp_proto;
+
+ int low = sepol_port_get_low(data);
+ int high = sepol_port_get_high(data);
+ int proto = sepol_port_get_proto(data);
+
+ tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
+ if (!tmp_port)
+ goto omem;
+
+ /* Process protocol */
+ tmp_proto = sepol2ipproto(handle, proto);
+ if (tmp_proto < 0)
+ goto err;
+ tmp_port->u.port.protocol = tmp_proto;
+
+ /* Port range */
+ tmp_port->u.port.low_port = low;
+ tmp_port->u.port.high_port = high;
+ if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
+ ERR(handle, "low port %d exceeds high port %d",
+ tmp_port->u.port.low_port, tmp_port->u.port.high_port);
+ goto err;
+ }
+
+ /* Context */
+ if (context_from_record(handle, policydb, &tmp_con,
+ sepol_port_get_con(data)) < 0)
+ goto err;
+ context_cpy(&tmp_port->context[0], tmp_con);
+ context_destroy(tmp_con);
+ free(tmp_con);
+ tmp_con = NULL;
+
+ *port = tmp_port;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ if (tmp_port != NULL) {
+ context_destroy(&tmp_port->context[0]);
+ free(tmp_port);
+ }
+ context_destroy(tmp_con);
+ free(tmp_con);
+ ERR(handle, "could not create port structure for range %u:%u (%s)",
+ low, high, sepol_port_get_proto_str(proto));
+ return STATUS_ERR;
+}
+
+static int port_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ ocontext_t * port, sepol_port_t ** record)
+{
+
+ int proto = port->u.port.protocol;
+ int low = port->u.port.low_port;
+ int high = port->u.port.high_port;
+ context_struct_t *con = &port->context[0];
+ int rec_proto = -1;
+
+ sepol_context_t *tmp_con = NULL;
+ sepol_port_t *tmp_record = NULL;
+
+ if (sepol_port_create(handle, &tmp_record) < 0)
+ goto err;
+
+ rec_proto = ipproto2sepol(handle, proto);
+ if (rec_proto < 0)
+ goto err;
+
+ sepol_port_set_proto(tmp_record, rec_proto);
+ sepol_port_set_range(tmp_record, low, high);
+
+ if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+ goto err;
+
+ if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
+ goto err;
+
+ sepol_context_free(tmp_con);
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not convert port range %u - %u (%s) "
+ "to record", low, high, sepol_port_get_proto_str(rec_proto));
+ sepol_context_free(tmp_con);
+ sepol_port_free(tmp_record);
+ return STATUS_ERR;
+}
+
+/* Return the number of ports */
+extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ unsigned int count = 0;
+ ocontext_t *c, *head;
+ const policydb_t *policydb = &p->p;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c != NULL; c = c->next)
+ count++;
+
+ *response = count;
+
+ return STATUS_SUCCESS;
+}
+
+/* Check if a port exists */
+int sepol_port_exists(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_port_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int low, high, proto;
+ const char *proto_str;
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int proto2 = c->u.port.protocol;
+ int low2 = c->u.port.low_port;
+ int high2 = c->u.port.high_port;
+
+ if (proto == proto2 && low2 == low && high2 == high) {
+ *response = 1;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = 0;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not check if port range %u - %u (%s) exists",
+ low, high, proto_str);
+ return STATUS_ERR;
+}
+
+/* Query a port */
+int sepol_port_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_port_key_t * key, sepol_port_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+
+ int low, high, proto;
+ const char *proto_str;
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int proto2 = c->u.port.protocol;
+ int low2 = c->u.port.low_port;
+ int high2 = c->u.port.high_port;
+
+ if (proto == proto2 && low2 == low && high2 == high) {
+ if (port_to_record(handle, policydb, c, response) < 0)
+ goto err;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ *response = NULL;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query port range %u - %u (%s)",
+ low, high, proto_str);
+ return STATUS_ERR;
+
+}
+
+/* Load a port into policy */
+int sepol_port_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_port_key_t * key, const sepol_port_t * data)
+{
+
+ policydb_t *policydb = &p->p;
+ ocontext_t *port = NULL;
+
+ int low, high, proto;
+ const char *proto_str;
+
+ sepol_port_key_unpack(key, &low, &high, &proto);
+ proto_str = sepol_port_get_proto_str(proto);
+ proto = sepol2ipproto(handle, proto);
+ if (proto < 0)
+ goto err;
+
+ if (port_from_record(handle, policydb, &port, data) < 0)
+ goto err;
+
+ /* Attach to context list */
+ port->next = policydb->ocontexts[OCON_PORT];
+ policydb->ocontexts[OCON_PORT] = port;
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not load port range %u - %u (%s)",
+ low, high, proto_str);
+ if (port != NULL) {
+ context_destroy(&port->context[0]);
+ free(port);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_port_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_port_t * port,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ ocontext_t *c, *head;
+ sepol_port_t *port = NULL;
+
+ head = policydb->ocontexts[OCON_PORT];
+ for (c = head; c; c = c->next) {
+ int status;
+
+ if (port_to_record(handle, policydb, c, &port) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(port, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_port_free(port);
+ port = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over ports");
+ sepol_port_free(port);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/private.h b/libsepol/src/private.h
new file mode 100644
index 0000000..9c700c9
--- /dev/null
+++ b/libsepol/src/private.h
@@ -0,0 +1,64 @@
+/* Private definitions for libsepol. */
+
+/* Endian conversion for reading and writing binary policies */
+
+#include <sepol/policydb/policydb.h>
+
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#else
+#include <byteswap.h>
+#include <endian.h>
+#endif
+
+#include <errno.h>
+#include <dso.h>
+
+#ifdef __APPLE__
+#define __BYTE_ORDER BYTE_ORDER
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+#define le64_to_cpu(x) (x)
+#else
+#define cpu_to_le16(x) bswap_16(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#define le64_to_cpu(x) bswap_64(x)
+#endif
+
+#undef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+#undef max
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+/* Policy compatibility information. */
+struct policydb_compat_info {
+ unsigned int type;
+ unsigned int version;
+ unsigned int sym_num;
+ unsigned int ocon_num;
+ unsigned int target_platform;
+};
+
+extern struct policydb_compat_info *policydb_lookup_compat(unsigned int version,
+ unsigned int type,
+ unsigned int target_platform);
+
+/* Reading from a policy "file". */
+extern int next_entry(void *buf, struct policy_file *fp, size_t bytes) hidden;
+extern size_t put_entry(const void *ptr, size_t size, size_t n,
+ struct policy_file *fp) hidden;
diff --git a/libsepol/src/roles.c b/libsepol/src/roles.c
new file mode 100644
index 0000000..713d834
--- /dev/null
+++ b/libsepol/src/roles.c
@@ -0,0 +1,54 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/policydb.h>
+
+#include "debug.h"
+#include "handle.h"
+
+/* Check if a role exists */
+int sepol_role_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ sepol_policydb_t * p, const char *role, int *response)
+{
+
+ policydb_t *policydb = &p->p;
+ *response = (hashtab_search(policydb->p_roles.table,
+ (const hashtab_key_t)role) != NULL);
+
+ return STATUS_SUCCESS;
+}
+
+/* Fill an array with all valid roles */
+int sepol_role_list(sepol_handle_t * handle,
+ sepol_policydb_t * p, char ***roles, unsigned int *nroles)
+{
+
+ policydb_t *policydb = &p->p;
+ unsigned int tmp_nroles = policydb->p_roles.nprim;
+ char **tmp_roles = (char **)malloc(tmp_nroles * sizeof(char *));
+ char **ptr;
+ unsigned int i;
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < tmp_nroles; i++) {
+ tmp_roles[i] = strdup(policydb->p_role_val_to_name[i]);
+ if (!tmp_roles[i])
+ goto omem;
+ }
+
+ *nroles = tmp_nroles;
+ *roles = tmp_roles;
+
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not list roles");
+
+ ptr = tmp_roles;
+ while (ptr && *ptr)
+ free(*ptr++);
+ free(tmp_roles);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
new file mode 100644
index 0000000..d64a8e8
--- /dev/null
+++ b/libsepol/src/services.c
@@ -0,0 +1,2171 @@
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com>
+ * and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
+ *
+ * Fine-grained netlink support
+ * IPv6 support
+ * Code cleanup
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the security services.
+ */
+
+/* Initial sizes malloc'd for sepol_compute_av_reason_buffer() support */
+#define REASON_BUF_SIZE 2048
+#define EXPR_BUF_SIZE 1024
+#define STACK_LEN 32
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/sidtab.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/util.h>
+
+#include "debug.h"
+#include "private.h"
+#include "context.h"
+#include "av_permissions.h"
+#include "dso.h"
+#include "mls.h"
+
+#define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+#define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
+
+static int selinux_enforcing = 1;
+
+static sidtab_t mysidtab, *sidtab = &mysidtab;
+static policydb_t mypolicydb, *policydb = &mypolicydb;
+
+/* Used by sepol_compute_av_reason_buffer() to keep track of entries */
+static int reason_buf_used;
+static int reason_buf_len;
+
+/* Stack services for RPN to infix conversion. */
+static char **stack;
+static int stack_len;
+static int next_stack_entry;
+
+static void push(char *expr_ptr)
+{
+ if (next_stack_entry >= stack_len) {
+ char **new_stack = stack;
+ int new_stack_len;
+
+ if (stack_len == 0)
+ new_stack_len = STACK_LEN;
+ else
+ new_stack_len = stack_len * 2;
+
+ new_stack = realloc(stack, new_stack_len * sizeof(*stack));
+ if (!new_stack) {
+ ERR(NULL, "unable to allocate stack space");
+ return;
+ }
+ stack_len = new_stack_len;
+ stack = new_stack;
+ }
+ stack[next_stack_entry] = expr_ptr;
+ next_stack_entry++;
+}
+
+static char *pop(void)
+{
+ next_stack_entry--;
+ if (next_stack_entry < 0) {
+ next_stack_entry = 0;
+ ERR(NULL, "pop called with no stack entries");
+ return NULL;
+ }
+ return stack[next_stack_entry];
+}
+/* End Stack services */
+
+int hidden sepol_set_sidtab(sidtab_t * s)
+{
+ sidtab = s;
+ return 0;
+}
+
+int hidden sepol_set_policydb(policydb_t * p)
+{
+ policydb = p;
+ return 0;
+}
+
+int sepol_set_policydb_from_file(FILE * fp)
+{
+ struct policy_file pf;
+
+ policy_file_init(&pf);
+ pf.fp = fp;
+ pf.type = PF_USE_STDIO;
+ if (mypolicydb.policy_type)
+ policydb_destroy(&mypolicydb);
+ if (policydb_init(&mypolicydb)) {
+ ERR(NULL, "Out of memory!");
+ return -1;
+ }
+ if (policydb_read(&mypolicydb, &pf, 0)) {
+ policydb_destroy(&mypolicydb);
+ ERR(NULL, "can't read binary policy: %s", strerror(errno));
+ return -1;
+ }
+ policydb = &mypolicydb;
+ return sepol_sidtab_init(sidtab);
+}
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static uint32_t latest_granting = 0;
+
+/*
+ * cat_expr_buf adds a string to an expression buffer and handles
+ * realloc's if buffer is too small. The array of expression text
+ * buffer pointers and its counter are globally defined here as
+ * constraint_expr_eval_reason() sets them up and cat_expr_buf
+ * updates the e_buf pointer.
+ */
+static int expr_counter;
+static char **expr_list;
+static int expr_buf_used;
+static int expr_buf_len;
+
+static void cat_expr_buf(char *e_buf, const char *string)
+{
+ int len, new_buf_len;
+ char *p, *new_buf = e_buf;
+
+ while (1) {
+ p = e_buf + expr_buf_used;
+ len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string);
+ if (len < 0 || len >= expr_buf_len - expr_buf_used) {
+ new_buf_len = expr_buf_len + EXPR_BUF_SIZE;
+ new_buf = realloc(e_buf, new_buf_len);
+ if (!new_buf) {
+ ERR(NULL, "failed to realloc expr buffer");
+ return;
+ }
+ /* Update new ptr in expr list and locally + new len */
+ expr_list[expr_counter] = new_buf;
+ e_buf = new_buf;
+ expr_buf_len = new_buf_len;
+ } else {
+ expr_buf_used += len;
+ return;
+ }
+ }
+}
+
+/*
+ * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES,
+ * then for 'types' only, read the types_names->types list as it will
+ * contain a list of types and attributes that were defined in the
+ * policy source.
+ * For user and role plus types (for policy vers <
+ * POLICYDB_VERSION_CONSTRAINT_NAMES) just read the e->names list.
+ */
+static void get_name_list(constraint_expr_t *e, int type,
+ const char *src, const char *op, int failed)
+{
+ ebitmap_t *types;
+ int rc = 0;
+ unsigned int i;
+ char tmp_buf[128];
+ int counter = 0;
+
+ if (policydb->policy_type == POLICY_KERN &&
+ policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
+ type == CEXPR_TYPE)
+ types = &e->type_names->types;
+ else
+ types = &e->names;
+
+ /* Find out how many entries */
+ for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
+ rc = ebitmap_get_bit(types, i);
+ if (rc == 0)
+ continue;
+ else
+ counter++;
+ }
+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s%s", src, op);
+ cat_expr_buf(expr_list[expr_counter], tmp_buf);
+
+ if (counter == 0)
+ cat_expr_buf(expr_list[expr_counter], "<empty_set> ");
+ if (counter > 1)
+ cat_expr_buf(expr_list[expr_counter], " {");
+ if (counter >= 1) {
+ for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
+ rc = ebitmap_get_bit(types, i);
+ if (rc == 0)
+ continue;
+
+ /* Collect entries */
+ switch (type) {
+ case CEXPR_USER:
+ snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+ policydb->p_user_val_to_name[i]);
+ break;
+ case CEXPR_ROLE:
+ snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+ policydb->p_role_val_to_name[i]);
+ break;
+ case CEXPR_TYPE:
+ snprintf(tmp_buf, sizeof(tmp_buf), " %s",
+ policydb->p_type_val_to_name[i]);
+ break;
+ }
+ cat_expr_buf(expr_list[expr_counter], tmp_buf);
+ }
+ }
+ if (counter > 1)
+ cat_expr_buf(expr_list[expr_counter], " }");
+ if (failed)
+ cat_expr_buf(expr_list[expr_counter], " -Fail-) ");
+ else
+ cat_expr_buf(expr_list[expr_counter], ") ");
+
+ return;
+}
+
+static void msgcat(const char *src, const char *tgt, const char *op, int failed)
+{
+ char tmp_buf[128];
+ if (failed)
+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ",
+ src, op, tgt);
+ else
+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s) ",
+ src, op, tgt);
+ cat_expr_buf(expr_list[expr_counter], tmp_buf);
+}
+
+/* Returns a buffer with class, statement type and permissions */
+static char *get_class_info(sepol_security_class_t tclass,
+ constraint_node_t *constraint,
+ context_struct_t *xcontext)
+{
+ constraint_expr_t *e;
+ int mls, state_num;
+
+ /* Find if MLS statement or not */
+ mls = 0;
+ for (e = constraint->expr; e; e = e->next) {
+ if (e->attr >= CEXPR_L1L2) {
+ mls = 1;
+ break;
+ }
+ }
+
+ /* Determine statement type */
+ const char *statements[] = {
+ "constrain ", /* 0 */
+ "mlsconstrain ", /* 1 */
+ "validatetrans ", /* 2 */
+ "mlsvalidatetrans ", /* 3 */
+ 0 };
+
+ if (xcontext == NULL)
+ state_num = mls + 0;
+ else
+ state_num = mls + 2;
+
+ int class_buf_len = 0;
+ int new_class_buf_len;
+ int len, buf_used;
+ char *class_buf = NULL, *p;
+ char *new_class_buf = NULL;
+
+ while (1) {
+ new_class_buf_len = class_buf_len + EXPR_BUF_SIZE;
+ new_class_buf = realloc(class_buf, new_class_buf_len);
+ if (!new_class_buf)
+ return NULL;
+ class_buf_len = new_class_buf_len;
+ class_buf = new_class_buf;
+ buf_used = 0;
+ p = class_buf;
+
+ /* Add statement type */
+ len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]);
+ if (len < 0 || len >= class_buf_len - buf_used)
+ continue;
+
+ /* Add class entry */
+ p += len;
+ buf_used += len;
+ len = snprintf(p, class_buf_len - buf_used, "%s ",
+ policydb->p_class_val_to_name[tclass - 1]);
+ if (len < 0 || len >= class_buf_len - buf_used)
+ continue;
+
+ /* Add permission entries (validatetrans does not have perms) */
+ p += len;
+ buf_used += len;
+ if (state_num < 2) {
+ len = snprintf(p, class_buf_len - buf_used, "{%s } (",
+ sepol_av_to_string(policydb, tclass,
+ constraint->permissions));
+ } else {
+ len = snprintf(p, class_buf_len - buf_used, "(");
+ }
+ if (len < 0 || len >= class_buf_len - buf_used)
+ continue;
+ break;
+ }
+ return class_buf;
+}
+
+/*
+ * Modified version of constraint_expr_eval that will process each
+ * constraint as before but adds the information to text buffers that
+ * will hold various components. The expression will be in RPN format,
+ * therefore there is a stack based RPN to infix converter to produce
+ * the final readable constraint.
+ *
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast... It is used by the validatetrans rules
+ * only. For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the
+ * context of the process performing the transition. All other callers
+ * of constraint_expr_eval_reason should pass in NULL for xcontext.
+ *
+ * This function will also build a buffer as the constraint is processed
+ * for analysis. If this option is not required, then:
+ * 'tclass' should be '0' and r_buf MUST be NULL.
+ */
+static int constraint_expr_eval_reason(context_struct_t *scontext,
+ context_struct_t *tcontext,
+ context_struct_t *xcontext,
+ sepol_security_class_t tclass,
+ constraint_node_t *constraint,
+ char **r_buf,
+ unsigned int flags)
+{
+ uint32_t val1, val2;
+ context_struct_t *c;
+ role_datum_t *r1, *r2;
+ mls_level_t *l1, *l2;
+ constraint_expr_t *e;
+ int s[CEXPR_MAXDEPTH];
+ int sp = -1;
+ char tmp_buf[128];
+
+/*
+ * Define the s_t_x_num values that make up r1, t2 etc. in text strings
+ * Set 1 = source, 2 = target, 3 = xcontext for validatetrans
+ */
+#define SOURCE 1
+#define TARGET 2
+#define XTARGET 3
+
+ int s_t_x_num = SOURCE;
+
+ /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */
+ int u_r_t = 0;
+
+ char *src = NULL;
+ char *tgt = NULL;
+ int rc = 0, x;
+ char *class_buf = NULL;
+
+ /*
+ * The array of expression answer buffer pointers and counter.
+ */
+ char **answer_list = NULL;
+ int answer_counter = 0;
+
+ class_buf = get_class_info(tclass, constraint, xcontext);
+ if (!class_buf) {
+ ERR(NULL, "failed to allocate class buffer");
+ return -ENOMEM;
+ }
+
+ /* Original function but with buffer support */
+ int expr_list_len = 0;
+ expr_counter = 0;
+ expr_list = NULL;
+ for (e = constraint->expr; e; e = e->next) {
+ /* Allocate a stack to hold expression buffer entries */
+ if (expr_counter >= expr_list_len) {
+ char **new_expr_list = expr_list;
+ int new_expr_list_len;
+
+ if (expr_list_len == 0)
+ new_expr_list_len = STACK_LEN;
+ else
+ new_expr_list_len = expr_list_len * 2;
+
+ new_expr_list = realloc(expr_list,
+ new_expr_list_len * sizeof(*expr_list));
+ if (!new_expr_list) {
+ ERR(NULL, "failed to allocate expr buffer stack");
+ rc = -ENOMEM;
+ goto out;
+ }
+ expr_list_len = new_expr_list_len;
+ expr_list = new_expr_list;
+ }
+
+ /*
+ * malloc a buffer to store each expression text component. If
+ * buffer is too small cat_expr_buf() will realloc extra space.
+ */
+ expr_buf_len = EXPR_BUF_SIZE;
+ expr_list[expr_counter] = malloc(expr_buf_len);
+ if (!expr_list[expr_counter]) {
+ ERR(NULL, "failed to allocate expr buffer");
+ rc = -ENOMEM;
+ goto out;
+ }
+ expr_buf_used = 0;
+
+ /* Now process each expression of the constraint */
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ BUG_ON(sp < 0);
+ s[sp] = !s[sp];
+ cat_expr_buf(expr_list[expr_counter], "not");
+ break;
+ case CEXPR_AND:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] &= s[sp + 1];
+ cat_expr_buf(expr_list[expr_counter], "and");
+ break;
+ case CEXPR_OR:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] |= s[sp + 1];
+ cat_expr_buf(expr_list[expr_counter], "or");
+ break;
+ case CEXPR_ATTR:
+ if (sp == (CEXPR_MAXDEPTH - 1))
+ goto out;
+
+ switch (e->attr) {
+ case CEXPR_USER:
+ val1 = scontext->user;
+ val2 = tcontext->user;
+ free(src); src = strdup("u1");
+ free(tgt); tgt = strdup("u2");
+ break;
+ case CEXPR_TYPE:
+ val1 = scontext->type;
+ val2 = tcontext->type;
+ free(src); src = strdup("t1");
+ free(tgt); tgt = strdup("t2");
+ break;
+ case CEXPR_ROLE:
+ val1 = scontext->role;
+ val2 = tcontext->role;
+ r1 = policydb->role_val_to_struct[val1 - 1];
+ r2 = policydb->role_val_to_struct[val2 - 1];
+ free(src); src = strdup("r1");
+ free(tgt); tgt = strdup("r2");
+
+ switch (e->op) {
+ case CEXPR_DOM:
+ s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
+ msgcat(src, tgt, "dom", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
+ msgcat(src, tgt, "domby", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1)
+ && !ebitmap_get_bit(&r2->dominates, val1 - 1));
+ msgcat(src, tgt, "incomp", s[sp] == 0);
+ expr_counter++;
+ continue;
+ default:
+ break;
+ }
+ break;
+ case CEXPR_L1L2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[0]);
+ free(src); src = strdup("l1");
+ free(tgt); tgt = strdup("l2");
+ goto mls_ops;
+ case CEXPR_L1H2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ free(src); src = strdup("l1");
+ free(tgt); tgt = strdup("h2");
+ goto mls_ops;
+ case CEXPR_H1L2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[0]);
+ free(src); src = strdup("h1");
+ free(tgt); tgt = strdup("l2");
+ goto mls_ops;
+ case CEXPR_H1H2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[1]);
+ free(src); src = strdup("h1");
+ free(tgt); tgt = strdup("h2");
+ goto mls_ops;
+ case CEXPR_L1H1:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(scontext->range.level[1]);
+ free(src); src = strdup("l1");
+ free(tgt); tgt = strdup("h1");
+ goto mls_ops;
+ case CEXPR_L2H2:
+ l1 = &(tcontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ free(src); src = strdup("l2");
+ free(tgt); tgt = strdup("h2");
+mls_ops:
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = mls_level_eq(l1, l2);
+ msgcat(src, tgt, "eq", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_NEQ:
+ s[++sp] = !mls_level_eq(l1, l2);
+ msgcat(src, tgt, "!=", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_DOM:
+ s[++sp] = mls_level_dom(l1, l2);
+ msgcat(src, tgt, "dom", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = mls_level_dom(l2, l1);
+ msgcat(src, tgt, "domby", s[sp] == 0);
+ expr_counter++;
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = mls_level_incomp(l2, l1);
+ msgcat(src, tgt, "incomp", s[sp] == 0);
+ expr_counter++;
+ continue;
+ default:
+ BUG();
+ goto out;
+ }
+ break;
+ default:
+ BUG();
+ goto out;
+ }
+
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = (val1 == val2);
+ msgcat(src, tgt, "==", s[sp] == 0);
+ break;
+ case CEXPR_NEQ:
+ s[++sp] = (val1 != val2);
+ msgcat(src, tgt, "!=", s[sp] == 0);
+ break;
+ default:
+ BUG();
+ goto out;
+ }
+ break;
+ case CEXPR_NAMES:
+ if (sp == (CEXPR_MAXDEPTH - 1))
+ goto out;
+ s_t_x_num = SOURCE;
+ c = scontext;
+ if (e->attr & CEXPR_TARGET) {
+ s_t_x_num = TARGET;
+ c = tcontext;
+ } else if (e->attr & CEXPR_XTARGET) {
+ s_t_x_num = XTARGET;
+ c = xcontext;
+ }
+ if (!c) {
+ BUG();
+ goto out;
+ }
+ if (e->attr & CEXPR_USER) {
+ u_r_t = CEXPR_USER;
+ val1 = c->user;
+ snprintf(tmp_buf, sizeof(tmp_buf), "u%d ", s_t_x_num);
+ free(src); src = strdup(tmp_buf);
+ } else if (e->attr & CEXPR_ROLE) {
+ u_r_t = CEXPR_ROLE;
+ val1 = c->role;
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%d ", s_t_x_num);
+ free(src); src = strdup(tmp_buf);
+ } else if (e->attr & CEXPR_TYPE) {
+ u_r_t = CEXPR_TYPE;
+ val1 = c->type;
+ snprintf(tmp_buf, sizeof(tmp_buf), "t%d ", s_t_x_num);
+ free(src); src = strdup(tmp_buf);
+ } else {
+ BUG();
+ goto out;
+ }
+
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+ get_name_list(e, u_r_t, src, "==", s[sp] == 0);
+ break;
+
+ case CEXPR_NEQ:
+ s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+ get_name_list(e, u_r_t, src, "!=", s[sp] == 0);
+ break;
+ default:
+ BUG();
+ goto out;
+ }
+ break;
+ default:
+ BUG();
+ goto out;
+ }
+ expr_counter++;
+ }
+
+ /*
+ * At this point each expression of the constraint is in
+ * expr_list[n+1] and in RPN format. Now convert to 'infix'
+ */
+
+ /*
+ * Save expr count but zero expr_counter to detect if
+ * 'BUG(); goto out;' was called as we need to release any used
+ * expr_list malloc's. Normally they are released by the RPN to
+ * infix code.
+ */
+ int expr_count = expr_counter;
+ expr_counter = 0;
+
+ /*
+ * Generate the same number of answer buffer entries as expression
+ * buffers (as there will never be more).
+ */
+ answer_list = malloc(expr_count * sizeof(*answer_list));
+ if (!answer_list) {
+ ERR(NULL, "failed to allocate answer stack");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* The pop operands */
+ char *a;
+ char *b;
+ int a_len, b_len;
+
+ /* Convert constraint from RPN to infix notation. */
+ for (x = 0; x != expr_count; x++) {
+ if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x],
+ "or", 2) == 0) {
+ b = pop();
+ b_len = strlen(b);
+ a = pop();
+ a_len = strlen(a);
+
+ /* get a buffer to hold the answer */
+ answer_list[answer_counter] = malloc(a_len + b_len + 8);
+ if (!answer_list[answer_counter]) {
+ ERR(NULL, "failed to allocate answer buffer");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(answer_list[answer_counter], '\0', a_len + b_len + 8);
+
+ sprintf(answer_list[answer_counter], "%s %s %s", a,
+ expr_list[x], b);
+ push(answer_list[answer_counter++]);
+ free(a);
+ free(b);
+ free(expr_list[x]);
+ } else if (strncmp(expr_list[x], "not", 3) == 0) {
+ b = pop();
+ b_len = strlen(b);
+
+ answer_list[answer_counter] = malloc(b_len + 8);
+ if (!answer_list[answer_counter]) {
+ ERR(NULL, "failed to allocate answer buffer");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(answer_list[answer_counter], '\0', b_len + 8);
+
+ if (strncmp(b, "not", 3) == 0)
+ sprintf(answer_list[answer_counter], "%s (%s)",
+ expr_list[x], b);
+ else
+ sprintf(answer_list[answer_counter], "%s%s",
+ expr_list[x], b);
+ push(answer_list[answer_counter++]);
+ free(b);
+ free(expr_list[x]);
+ } else {
+ push(expr_list[x]);
+ }
+ }
+ /* Get the final answer from tos and build constraint text */
+ a = pop();
+
+ /* validatetrans / constraint calculation:
+ rc = 0 is denied, rc = 1 is granted */
+ sprintf(tmp_buf, "%s %s\n",
+ xcontext ? "Validatetrans" : "Constraint",
+ s[0] ? "GRANTED" : "DENIED");
+
+ int len, new_buf_len;
+ char *p, **new_buf = r_buf;
+ /*
+ * These contain the constraint components that are added to the
+ * callers reason buffer.
+ */
+ const char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 };
+
+ /*
+ * This will add the constraints to the callers reason buffer (who is
+ * responsible for freeing the memory). It will handle any realloc's
+ * should the buffer be too short.
+ * The reason_buf_used and reason_buf_len counters are defined
+ * globally as multiple constraints can be in the buffer.
+ */
+
+ if (r_buf && ((s[0] == 0) || ((s[0] == 1 &&
+ (flags & SHOW_GRANTED) == SHOW_GRANTED)))) {
+ for (x = 0; buffers[x] != NULL; x++) {
+ while (1) {
+ p = *r_buf + reason_buf_used;
+ len = snprintf(p, reason_buf_len - reason_buf_used,
+ "%s", buffers[x]);
+ if (len < 0 || len >= reason_buf_len - reason_buf_used) {
+ new_buf_len = reason_buf_len + REASON_BUF_SIZE;
+ *new_buf = realloc(*r_buf, new_buf_len);
+ if (!new_buf) {
+ ERR(NULL, "failed to realloc reason buffer");
+ goto out1;
+ }
+ **r_buf = **new_buf;
+ reason_buf_len = new_buf_len;
+ continue;
+ } else {
+ reason_buf_used += len;
+ break;
+ }
+ }
+ }
+ }
+
+out1:
+ rc = s[0];
+ free(a);
+
+out:
+ free(class_buf);
+ free(src);
+ free(tgt);
+
+ if (expr_counter) {
+ for (x = 0; expr_list[x] != NULL; x++)
+ free(expr_list[x]);
+ }
+ free(answer_list);
+ free(expr_list);
+ return rc;
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(context_struct_t * scontext,
+ context_struct_t * tcontext,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason,
+ char **r_buf,
+ unsigned int flags)
+{
+ constraint_node_t *constraint;
+ struct role_allow *ra;
+ avtab_key_t avkey;
+ class_datum_t *tclass_datum;
+ avtab_ptr_t node;
+ ebitmap_t *sattr, *tattr;
+ ebitmap_node_t *snode, *tnode;
+ unsigned int i, j;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ /*
+ * Initialize the access vectors to the default values.
+ */
+ avd->allowed = 0;
+ avd->decided = 0xffffffff;
+ avd->auditallow = 0;
+ avd->auditdeny = 0xffffffff;
+ avd->seqno = latest_granting;
+ *reason = 0;
+
+ /*
+ * If a specific type enforcement rule was defined for
+ * this permission check, then use it.
+ */
+ avkey.target_class = tclass;
+ avkey.specified = AVTAB_AV;
+ sattr = &policydb->type_attr_map[scontext->type - 1];
+ tattr = &policydb->type_attr_map[tcontext->type - 1];
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ avkey.source_type = i + 1;
+ avkey.target_type = j + 1;
+ for (node =
+ avtab_search_node(&policydb->te_avtab, &avkey);
+ node != NULL;
+ node =
+ avtab_search_node_next(node, avkey.specified)) {
+ if (node->key.specified == AVTAB_ALLOWED)
+ avd->allowed |= node->datum.data;
+ else if (node->key.specified ==
+ AVTAB_AUDITALLOW)
+ avd->auditallow |= node->datum.data;
+ else if (node->key.specified == AVTAB_AUDITDENY)
+ avd->auditdeny &= node->datum.data;
+ }
+
+ /* Check conditional av table for additional permissions */
+ cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
+
+ }
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_TE;
+ requested &= avd->allowed;
+ }
+
+ /*
+ * Remove any permissions prohibited by a constraint (this includes
+ * the MLS policy).
+ */
+ constraint = tclass_datum->constraints;
+ while (constraint) {
+ if ((constraint->permissions & (avd->allowed)) &&
+ !constraint_expr_eval_reason(scontext, tcontext, NULL,
+ tclass, constraint, r_buf, flags)) {
+ avd->allowed =
+ (avd->allowed) & ~(constraint->permissions);
+ }
+ constraint = constraint->next;
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_CONS;
+ requested &= avd->allowed;
+ }
+
+ /*
+ * If checking process transition permission and the
+ * role is changing, then check the (current_role, new_role)
+ * pair.
+ */
+ if (tclass == SECCLASS_PROCESS &&
+ (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
+ scontext->role != tcontext->role) {
+ for (ra = policydb->role_allow; ra; ra = ra->next) {
+ if (scontext->role == ra->role &&
+ tcontext->role == ra->new_role)
+ break;
+ }
+ if (!ra)
+ avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
+ PROCESS__DYNTRANSITION);
+ }
+
+ if (requested & ~avd->allowed) {
+ *reason |= SEPOL_COMPUTEAV_RBAC;
+ requested &= avd->allowed;
+ }
+
+ return 0;
+}
+
+int hidden sepol_validate_transition(sepol_security_id_t oldsid,
+ sepol_security_id_t newsid,
+ sepol_security_id_t tasksid,
+ sepol_security_class_t tclass)
+{
+ context_struct_t *ocontext;
+ context_struct_t *ncontext;
+ context_struct_t *tcontext;
+ class_datum_t *tclass_datum;
+ constraint_node_t *constraint;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ ocontext = sepol_sidtab_search(sidtab, oldsid);
+ if (!ocontext) {
+ ERR(NULL, "unrecognized SID %d", oldsid);
+ return -EINVAL;
+ }
+
+ ncontext = sepol_sidtab_search(sidtab, newsid);
+ if (!ncontext) {
+ ERR(NULL, "unrecognized SID %d", newsid);
+ return -EINVAL;
+ }
+
+ tcontext = sepol_sidtab_search(sidtab, tasksid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tasksid);
+ return -EINVAL;
+ }
+
+ constraint = tclass_datum->validatetrans;
+ while (constraint) {
+ if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
+ 0, constraint, NULL, 0)) {
+ return -EPERM;
+ }
+ constraint = constraint->next;
+ }
+
+ return 0;
+}
+
+/*
+ * sepol_validate_transition_reason_buffer - the reason buffer is realloc'd
+ * in the constraint_expr_eval_reason() function.
+ */
+int hidden sepol_validate_transition_reason_buffer(sepol_security_id_t oldsid,
+ sepol_security_id_t newsid,
+ sepol_security_id_t tasksid,
+ sepol_security_class_t tclass,
+ char **reason_buf,
+ unsigned int flags)
+{
+ context_struct_t *ocontext;
+ context_struct_t *ncontext;
+ context_struct_t *tcontext;
+ class_datum_t *tclass_datum;
+ constraint_node_t *constraint;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ ocontext = sepol_sidtab_search(sidtab, oldsid);
+ if (!ocontext) {
+ ERR(NULL, "unrecognized SID %d", oldsid);
+ return -EINVAL;
+ }
+
+ ncontext = sepol_sidtab_search(sidtab, newsid);
+ if (!ncontext) {
+ ERR(NULL, "unrecognized SID %d", newsid);
+ return -EINVAL;
+ }
+
+ tcontext = sepol_sidtab_search(sidtab, tasksid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tasksid);
+ return -EINVAL;
+ }
+
+ /*
+ * Set the buffer to NULL as mls/validatetrans may not be processed.
+ * If a buffer is required, then the routines in
+ * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE
+ * chunks (as it gets called for each mls/validatetrans processed).
+ * We just make sure these start from zero.
+ */
+ *reason_buf = NULL;
+ reason_buf_used = 0;
+ reason_buf_len = 0;
+ constraint = tclass_datum->validatetrans;
+ while (constraint) {
+ if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
+ tclass, constraint, reason_buf, flags)) {
+ return -EPERM;
+ }
+ constraint = constraint->next;
+ }
+ return 0;
+}
+
+int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason)
+{
+ context_struct_t *scontext = 0, *tcontext = 0;
+ int rc = 0;
+
+ scontext = sepol_sidtab_search(sidtab, ssid);
+ if (!scontext) {
+ ERR(NULL, "unrecognized SID %d", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sepol_sidtab_search(sidtab, tsid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
+ requested, avd, reason, NULL, 0);
+ out:
+ return rc;
+}
+
+/*
+ * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to
+ * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd
+ * in the constraint_expr_eval_reason() function.
+ */
+int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd,
+ unsigned int *reason,
+ char **reason_buf,
+ unsigned int flags)
+{
+ context_struct_t *scontext = 0, *tcontext = 0;
+ int rc = 0;
+
+ scontext = sepol_sidtab_search(sidtab, ssid);
+ if (!scontext) {
+ ERR(NULL, "unrecognized SID %d", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sepol_sidtab_search(sidtab, tsid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Set the buffer to NULL as constraints may not be processed.
+ * If a buffer is required, then the routines in
+ * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE
+ * chunks (as it gets called for each constraint processed).
+ * We just make sure these start from zero.
+ */
+ *reason_buf = NULL;
+ reason_buf_used = 0;
+ reason_buf_len = 0;
+
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
+ requested, avd, reason, reason_buf, flags);
+out:
+ return rc;
+}
+
+int hidden sepol_compute_av(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_access_vector_t requested,
+ struct sepol_av_decision *avd)
+{
+ unsigned int reason = 0;
+ return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
+ &reason);
+}
+
+/*
+ * Return a class ID associated with the class string specified by
+ * class_name.
+ */
+int hidden sepol_string_to_security_class(const char *class_name,
+ sepol_security_class_t *tclass)
+{
+ char *class = NULL;
+ sepol_security_class_t id;
+
+ for (id = 1;; id++) {
+ class = policydb->p_class_val_to_name[id - 1];
+ if (class == NULL) {
+ ERR(NULL, "could not convert %s to class id", class_name);
+ return STATUS_ERR;
+ }
+ if ((strcmp(class, class_name)) == 0) {
+ *tclass = id;
+ return STATUS_SUCCESS;
+ }
+ }
+}
+
+/*
+ * Return access vector bit associated with the class ID and permission
+ * string.
+ */
+int hidden sepol_string_to_av_perm(sepol_security_class_t tclass,
+ const char *perm_name,
+ sepol_access_vector_t *av)
+{
+ class_datum_t *tclass_datum;
+ perm_datum_t *perm_datum;
+
+ if (!tclass || tclass > policydb->p_classes.nprim) {
+ ERR(NULL, "unrecognized class %d", tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
+
+ /* Check for unique perms then the common ones (if any) */
+ perm_datum = (perm_datum_t *)
+ hashtab_search(tclass_datum->permissions.table,
+ (hashtab_key_t)perm_name);
+ if (perm_datum != NULL) {
+ *av = 0x1 << (perm_datum->s.value - 1);
+ return STATUS_SUCCESS;
+ }
+
+ if (tclass_datum->comdatum == NULL)
+ goto out;
+
+ perm_datum = (perm_datum_t *)
+ hashtab_search(tclass_datum->comdatum->permissions.table,
+ (hashtab_key_t)perm_name);
+
+ if (perm_datum != NULL) {
+ *av = 0x1 << (perm_datum->s.value - 1);
+ return STATUS_SUCCESS;
+ }
+out:
+ ERR(NULL, "could not convert %s to av bit", perm_name);
+ return STATUS_ERR;
+}
+
+/*
+ * Write the security context string representation of
+ * the context associated with `sid' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+int hidden sepol_sid_to_context(sepol_security_id_t sid,
+ sepol_security_context_t * scontext,
+ size_t * scontext_len)
+{
+ context_struct_t *context;
+ int rc = 0;
+
+ context = sepol_sidtab_search(sidtab, sid);
+ if (!context) {
+ ERR(NULL, "unrecognized SID %d", sid);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
+ out:
+ return rc;
+
+}
+
+/*
+ * Return a SID associated with the security context that
+ * has the string representation specified by `scontext'.
+ */
+int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
+ size_t scontext_len, sepol_security_id_t * sid)
+{
+
+ context_struct_t *context = NULL;
+
+ /* First, create the context */
+ if (context_from_string(NULL, policydb, &context,
+ scontext, scontext_len) < 0)
+ goto err;
+
+ /* Obtain the new sid */
+ if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
+ goto err;
+
+ context_destroy(context);
+ free(context);
+ return STATUS_SUCCESS;
+
+ err:
+ if (context) {
+ context_destroy(context);
+ free(context);
+ }
+ ERR(NULL, "could not convert %s to sid", scontext);
+ return STATUS_ERR;
+}
+
+static inline int compute_sid_handle_invalid_context(context_struct_t *
+ scontext,
+ context_struct_t *
+ tcontext,
+ sepol_security_class_t
+ tclass,
+ context_struct_t *
+ newcontext)
+{
+ if (selinux_enforcing) {
+ return -EACCES;
+ } else {
+ sepol_security_context_t s, t, n;
+ size_t slen, tlen, nlen;
+
+ context_to_string(NULL, policydb, scontext, &s, &slen);
+ context_to_string(NULL, policydb, tcontext, &t, &tlen);
+ context_to_string(NULL, policydb, newcontext, &n, &nlen);
+ ERR(NULL, "invalid context %s for "
+ "scontext=%s tcontext=%s tclass=%s",
+ n, s, t, policydb->p_class_val_to_name[tclass - 1]);
+ free(s);
+ free(t);
+ free(n);
+ return 0;
+ }
+}
+
+static int sepol_compute_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ uint32_t specified, sepol_security_id_t * out_sid)
+{
+ context_struct_t *scontext = 0, *tcontext = 0, newcontext;
+ struct role_trans *roletr = 0;
+ avtab_key_t avkey;
+ avtab_datum_t *avdatum;
+ avtab_ptr_t node;
+ int rc = 0;
+
+ scontext = sepol_sidtab_search(sidtab, ssid);
+ if (!scontext) {
+ ERR(NULL, "unrecognized SID %d", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sepol_sidtab_search(sidtab, tsid);
+ if (!tcontext) {
+ ERR(NULL, "unrecognized SID %d", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ context_init(&newcontext);
+
+ /* Set the user identity. */
+ switch (specified) {
+ case AVTAB_TRANSITION:
+ case AVTAB_CHANGE:
+ /* Use the process user identity. */
+ newcontext.user = scontext->user;
+ break;
+ case AVTAB_MEMBER:
+ /* Use the related object owner. */
+ newcontext.user = tcontext->user;
+ break;
+ }
+
+ /* Set the role and type to default values. */
+ switch (tclass) {
+ case SECCLASS_PROCESS:
+ /* Use the current role and type of process. */
+ newcontext.role = scontext->role;
+ newcontext.type = scontext->type;
+ break;
+ default:
+ /* Use the well-defined object role. */
+ newcontext.role = OBJECT_R_VAL;
+ /* Use the type of the related object. */
+ newcontext.type = tcontext->type;
+ }
+
+ /* Look for a type transition/member/change rule. */
+ avkey.source_type = scontext->type;
+ avkey.target_type = tcontext->type;
+ avkey.target_class = tclass;
+ avkey.specified = specified;
+ avdatum = avtab_search(&policydb->te_avtab, &avkey);
+
+ /* If no permanent rule, also check for enabled conditional rules */
+ if (!avdatum) {
+ node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
+ for (; node != NULL;
+ node = avtab_search_node_next(node, specified)) {
+ if (node->key.specified & AVTAB_ENABLED) {
+ avdatum = &node->datum;
+ break;
+ }
+ }
+ }
+
+ if (avdatum) {
+ /* Use the type from the type transition/member/change rule. */
+ newcontext.type = avdatum->data;
+ }
+
+ /* Check for class-specific changes. */
+ switch (tclass) {
+ case SECCLASS_PROCESS:
+ if (specified & AVTAB_TRANSITION) {
+ /* Look for a role transition rule. */
+ for (roletr = policydb->role_tr; roletr;
+ roletr = roletr->next) {
+ if (roletr->role == scontext->role &&
+ roletr->type == tcontext->type) {
+ /* Use the role transition rule. */
+ newcontext.role = roletr->new_role;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Set the MLS attributes.
+ This is done last because it may allocate memory. */
+ rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
+ &newcontext);
+ if (rc)
+ goto out;
+
+ /* Check the validity of the context. */
+ if (!policydb_context_isvalid(policydb, &newcontext)) {
+ rc = compute_sid_handle_invalid_context(scontext,
+ tcontext,
+ tclass, &newcontext);
+ if (rc)
+ goto out;
+ }
+ /* Obtain the sid for the context. */
+ rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
+ out:
+ context_destroy(&newcontext);
+ return rc;
+}
+
+/*
+ * Compute a SID to use for labeling a new object in the
+ * class `tclass' based on a SID pair.
+ */
+int hidden sepol_transition_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/*
+ * Compute a SID to use when selecting a member of a
+ * polyinstantiated object of class `tclass' based on
+ * a SID pair.
+ */
+int hidden sepol_member_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/*
+ * Compute a SID to use for relabeling an object in the
+ * class `tclass' based on a SID pair.
+ */
+int hidden sepol_change_sid(sepol_security_id_t ssid,
+ sepol_security_id_t tsid,
+ sepol_security_class_t tclass,
+ sepol_security_id_t * out_sid)
+{
+ return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+ hashtab_t h;
+ perm_datum_t *perdatum, *perdatum2;
+
+ h = (hashtab_t) p;
+ perdatum = (perm_datum_t *) datum;
+
+ perdatum2 = (perm_datum_t *) hashtab_search(h, key);
+ if (!perdatum2) {
+ ERR(NULL, "permission %s disappeared", key);
+ return -1;
+ }
+ if (perdatum->s.value != perdatum2->s.value) {
+ ERR(NULL, "the value of permissions %s changed", key);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ */
+static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+ policydb_t *newp;
+ class_datum_t *cladatum, *cladatum2;
+
+ newp = (policydb_t *) p;
+ cladatum = (class_datum_t *) datum;
+
+ cladatum2 =
+ (class_datum_t *) hashtab_search(newp->p_classes.table, key);
+ if (!cladatum2) {
+ ERR(NULL, "class %s disappeared", key);
+ return -1;
+ }
+ if (cladatum->s.value != cladatum2->s.value) {
+ ERR(NULL, "the value of class %s changed", key);
+ return -1;
+ }
+ if ((cladatum->comdatum && !cladatum2->comdatum) ||
+ (!cladatum->comdatum && cladatum2->comdatum)) {
+ ERR(NULL, "the inherits clause for the access "
+ "vector definition for class %s changed", key);
+ return -1;
+ }
+ if (cladatum->comdatum) {
+ if (hashtab_map
+ (cladatum->comdatum->permissions.table, validate_perm,
+ cladatum2->comdatum->permissions.table)) {
+ ERR(NULL,
+ " in the access vector definition "
+ "for class %s\n", key);
+ return -1;
+ }
+ }
+ if (hashtab_map(cladatum->permissions.table, validate_perm,
+ cladatum2->permissions.table)) {
+ ERR(NULL, " in access vector definition for class %s", key);
+ return -1;
+ }
+ return 0;
+}
+
+/* Clone the SID into the new SID table. */
+static int clone_sid(sepol_security_id_t sid,
+ context_struct_t * context, void *arg)
+{
+ sidtab_t *s = arg;
+
+ return sepol_sidtab_insert(s, sid, context);
+}
+
+static inline int convert_context_handle_invalid_context(context_struct_t *
+ context)
+{
+ if (selinux_enforcing) {
+ return -EINVAL;
+ } else {
+ sepol_security_context_t s;
+ size_t len;
+
+ context_to_string(NULL, policydb, context, &s, &len);
+ ERR(NULL, "context %s is invalid", s);
+ free(s);
+ return 0;
+ }
+}
+
+typedef struct {
+ policydb_t *oldp;
+ policydb_t *newp;
+} convert_context_args_t;
+
+/*
+ * Convert the values in the security context
+ * structure `c' from the values specified
+ * in the policy `p->oldp' to the values specified
+ * in the policy `p->newp'. Verify that the
+ * context is valid under the new policy.
+ */
+static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
+ context_struct_t * c, void *p)
+{
+ convert_context_args_t *args;
+ context_struct_t oldc;
+ role_datum_t *role;
+ type_datum_t *typdatum;
+ user_datum_t *usrdatum;
+ sepol_security_context_t s;
+ size_t len;
+ int rc = -EINVAL;
+
+ args = (convert_context_args_t *) p;
+
+ if (context_cpy(&oldc, c))
+ return -ENOMEM;
+
+ /* Convert the user. */
+ usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
+ args->oldp->
+ p_user_val_to_name[c->user -
+ 1]);
+
+ if (!usrdatum) {
+ goto bad;
+ }
+ c->user = usrdatum->s.value;
+
+ /* Convert the role. */
+ role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
+ args->oldp->
+ p_role_val_to_name[c->role - 1]);
+ if (!role) {
+ goto bad;
+ }
+ c->role = role->s.value;
+
+ /* Convert the type. */
+ typdatum = (type_datum_t *)
+ hashtab_search(args->newp->p_types.table,
+ args->oldp->p_type_val_to_name[c->type - 1]);
+ if (!typdatum) {
+ goto bad;
+ }
+ c->type = typdatum->s.value;
+
+ rc = mls_convert_context(args->oldp, args->newp, c);
+ if (rc)
+ goto bad;
+
+ /* Check the validity of the new context. */
+ if (!policydb_context_isvalid(args->newp, c)) {
+ rc = convert_context_handle_invalid_context(&oldc);
+ if (rc)
+ goto bad;
+ }
+
+ context_destroy(&oldc);
+ return 0;
+
+ bad:
+ context_to_string(NULL, policydb, &oldc, &s, &len);
+ context_destroy(&oldc);
+ ERR(NULL, "invalidating context %s", s);
+ free(s);
+ return rc;
+}
+
+/* Reading from a policy "file". */
+int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
+{
+ size_t nread;
+
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ nread = fread(buf, bytes, 1, fp->fp);
+
+ if (nread != 1)
+ return -1;
+ break;
+ case PF_USE_MEMORY:
+ if (bytes > fp->len)
+ return -1;
+ memcpy(buf, fp->data, bytes);
+ fp->data += bytes;
+ fp->len -= bytes;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+size_t hidden put_entry(const void *ptr, size_t size, size_t n,
+ struct policy_file *fp)
+{
+ size_t bytes = size * n;
+
+ switch (fp->type) {
+ case PF_USE_STDIO:
+ return fwrite(ptr, size, n, fp->fp);
+ case PF_USE_MEMORY:
+ if (bytes > fp->len) {
+ errno = ENOSPC;
+ return 0;
+ }
+
+ memcpy(fp->data, ptr, bytes);
+ fp->data += bytes;
+ fp->len -= bytes;
+ return n;
+ case PF_LEN:
+ fp->len += bytes;
+ return n;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * Read a new set of configuration data from
+ * a policy database binary representation file.
+ *
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ *
+ * Convert the context structures in the SID table to the
+ * new representation and verify that all entries
+ * in the SID table are valid under the new policy.
+ *
+ * Change the active policy database to use the new
+ * configuration data.
+ *
+ * Reset the access vector cache.
+ */
+int hidden sepol_load_policy(void *data, size_t len)
+{
+ policydb_t oldpolicydb, newpolicydb;
+ sidtab_t oldsidtab, newsidtab;
+ convert_context_args_t args;
+ int rc = 0;
+ struct policy_file file, *fp;
+
+ policy_file_init(&file);
+ file.type = PF_USE_MEMORY;
+ file.data = data;
+ file.len = len;
+ fp = &file;
+
+ if (policydb_init(&newpolicydb))
+ return -ENOMEM;
+
+ if (policydb_read(&newpolicydb, fp, 1)) {
+ policydb_destroy(&mypolicydb);
+ return -EINVAL;
+ }
+
+ sepol_sidtab_init(&newsidtab);
+
+ /* Verify that the existing classes did not change. */
+ if (hashtab_map
+ (policydb->p_classes.table, validate_class, &newpolicydb)) {
+ ERR(NULL, "the definition of an existing class changed");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Clone the SID table. */
+ sepol_sidtab_shutdown(sidtab);
+ if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /* Convert the internal representations of contexts
+ in the new SID table and remove invalid SIDs. */
+ args.oldp = policydb;
+ args.newp = &newpolicydb;
+ sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+
+ /* Save the old policydb and SID table to free later. */
+ memcpy(&oldpolicydb, policydb, sizeof *policydb);
+ sepol_sidtab_set(&oldsidtab, sidtab);
+
+ /* Install the new policydb and SID table. */
+ memcpy(policydb, &newpolicydb, sizeof *policydb);
+ sepol_sidtab_set(sidtab, &newsidtab);
+
+ /* Free the old policydb and SID table. */
+ policydb_destroy(&oldpolicydb);
+ sepol_sidtab_destroy(&oldsidtab);
+
+ return 0;
+
+ err:
+ sepol_sidtab_destroy(&newsidtab);
+ policydb_destroy(&newpolicydb);
+ return rc;
+
+}
+
+/*
+ * Return the SIDs to use for an unlabeled file system
+ * that is being mounted from the device with the
+ * the kdevname `name'. The `fs_sid' SID is returned for
+ * the file system and the `file_sid' SID is returned
+ * for all files within that file system.
+ */
+int hidden sepol_fs_sid(char *name,
+ sepol_security_id_t * fs_sid,
+ sepol_security_id_t * file_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_FS];
+ while (c) {
+ if (strcmp(c->u.name, name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0] || !c->sid[1]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[1],
+ &c->sid[1]);
+ if (rc)
+ goto out;
+ }
+ *fs_sid = c->sid[0];
+ *file_sid = c->sid[1];
+ } else {
+ *fs_sid = SECINITSID_FS;
+ *file_sid = SECINITSID_FILE;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SID of the port specified by
+ * `domain', `type', `protocol', and `port'.
+ */
+int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
+ uint16_t type __attribute__ ((unused)),
+ uint8_t protocol,
+ uint16_t port, sepol_security_id_t * out_sid)
+{
+ ocontext_t *c;
+ int rc = 0;
+
+ c = policydb->ocontexts[OCON_PORT];
+ while (c) {
+ if (c->u.port.protocol == protocol &&
+ c->u.port.low_port <= port && c->u.port.high_port >= port)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *out_sid = c->sid[0];
+ } else {
+ *out_sid = SECINITSID_PORT;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SIDs to use for a network interface
+ * with the name `name'. The `if_sid' SID is returned for
+ * the interface and the `msg_sid' SID is returned as
+ * the default SID for messages received on the
+ * interface.
+ */
+int hidden sepol_netif_sid(char *name,
+ sepol_security_id_t * if_sid,
+ sepol_security_id_t * msg_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_NETIF];
+ while (c) {
+ if (strcmp(name, c->u.name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ if (!c->sid[0] || !c->sid[1]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[1],
+ &c->sid[1]);
+ if (rc)
+ goto out;
+ }
+ *if_sid = c->sid[0];
+ *msg_sid = c->sid[1];
+ } else {
+ *if_sid = SECINITSID_NETIF;
+ *msg_sid = SECINITSID_NETMSG;
+ }
+
+ out:
+ return rc;
+}
+
+static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
+ uint32_t * mask)
+{
+ int i, fail = 0;
+
+ for (i = 0; i < 4; i++)
+ if (addr[i] != (input[i] & mask[i])) {
+ fail = 1;
+ break;
+ }
+
+ return !fail;
+}
+
+/*
+ * Return the SID of the node specified by the address
+ * `addrp' where `addrlen' is the length of the address
+ * in bytes and `domain' is the communications domain or
+ * address family in which the address should be interpreted.
+ */
+int hidden sepol_node_sid(uint16_t domain,
+ void *addrp,
+ size_t addrlen, sepol_security_id_t * out_sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ switch (domain) {
+ case AF_INET:{
+ uint32_t addr;
+
+ if (addrlen != sizeof(uint32_t)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ addr = *((uint32_t *) addrp);
+
+ c = policydb->ocontexts[OCON_NODE];
+ while (c) {
+ if (c->u.node.addr == (addr & c->u.node.mask))
+ break;
+ c = c->next;
+ }
+ break;
+ }
+
+ case AF_INET6:
+ if (addrlen != sizeof(uint64_t) * 2) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ c = policydb->ocontexts[OCON_NODE6];
+ while (c) {
+ if (match_ipv6_addrmask(addrp, c->u.node6.addr,
+ c->u.node6.mask))
+ break;
+ c = c->next;
+ }
+ break;
+
+ default:
+ *out_sid = SECINITSID_NODE;
+ goto out;
+ }
+
+ if (c) {
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *out_sid = c->sid[0];
+ } else {
+ *out_sid = SECINITSID_NODE;
+ }
+
+ out:
+ return rc;
+}
+
+/*
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by `fromsid'.
+ * Set `*sids' to point to a dynamically allocated
+ * array containing the set of SIDs. Set `*nel' to the
+ * number of elements in the array.
+ */
+#define SIDS_NEL 25
+
+int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
+ char *username,
+ sepol_security_id_t ** sids, uint32_t * nel)
+{
+ context_struct_t *fromcon, usercon;
+ sepol_security_id_t *mysids, *mysids2, sid;
+ uint32_t mynel = 0, maxnel = SIDS_NEL;
+ user_datum_t *user;
+ role_datum_t *role;
+ struct sepol_av_decision avd;
+ int rc = 0;
+ unsigned int i, j, reason;
+ ebitmap_node_t *rnode, *tnode;
+
+ fromcon = sepol_sidtab_search(sidtab, fromsid);
+ if (!fromcon) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ user = (user_datum_t *) hashtab_search(policydb->p_users.table,
+ username);
+ if (!user) {
+ rc = -EINVAL;
+ goto out;
+ }
+ usercon.user = user->s.value;
+
+ mysids = malloc(maxnel * sizeof(sepol_security_id_t));
+ if (!mysids) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
+
+ ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
+ continue;
+ role = policydb->role_val_to_struct[i];
+ usercon.role = i + 1;
+ ebitmap_for_each_bit(&role->types.types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ usercon.type = j + 1;
+ if (usercon.type == fromcon->type)
+ continue;
+
+ if (mls_setup_user_range
+ (fromcon, user, &usercon, policydb->mls))
+ continue;
+
+ rc = context_struct_compute_av(fromcon, &usercon,
+ SECCLASS_PROCESS,
+ PROCESS__TRANSITION,
+ &avd, &reason, NULL, 0);
+ if (rc || !(avd.allowed & PROCESS__TRANSITION))
+ continue;
+ rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
+ &sid);
+ if (rc) {
+ free(mysids);
+ goto out;
+ }
+ if (mynel < maxnel) {
+ mysids[mynel++] = sid;
+ } else {
+ maxnel += SIDS_NEL;
+ mysids2 =
+ malloc(maxnel *
+ sizeof(sepol_security_id_t));
+
+ if (!mysids2) {
+ rc = -ENOMEM;
+ free(mysids);
+ goto out;
+ }
+ memset(mysids2, 0,
+ maxnel * sizeof(sepol_security_id_t));
+ memcpy(mysids2, mysids,
+ mynel * sizeof(sepol_security_id_t));
+ free(mysids);
+ mysids = mysids2;
+ mysids[mynel++] = sid;
+ }
+ }
+ }
+
+ *sids = mysids;
+ *nel = mynel;
+
+ out:
+ return rc;
+}
+
+/*
+ * Return the SID to use for a file in a filesystem
+ * that cannot support a persistent label mapping or use another
+ * fixed labeling behavior like transition SIDs or task SIDs.
+ */
+int hidden sepol_genfs_sid(const char *fstype,
+ const char *path,
+ sepol_security_class_t sclass,
+ sepol_security_id_t * sid)
+{
+ size_t len;
+ genfs_t *genfs;
+ ocontext_t *c;
+ int rc = 0, cmp = 0;
+
+ for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
+ cmp = strcmp(fstype, genfs->fstype);
+ if (cmp <= 0)
+ break;
+ }
+
+ if (!genfs || cmp) {
+ *sid = SECINITSID_UNLABELED;
+ rc = -ENOENT;
+ goto out;
+ }
+
+ for (c = genfs->head; c; c = c->next) {
+ len = strlen(c->u.name);
+ if ((!c->v.sclass || sclass == c->v.sclass) &&
+ (strncmp(c->u.name, path, len) == 0))
+ break;
+ }
+
+ if (!c) {
+ *sid = SECINITSID_UNLABELED;
+ rc = -ENOENT;
+ goto out;
+ }
+
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0], &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+
+ *sid = c->sid[0];
+ out:
+ return rc;
+}
+
+int hidden sepol_fs_use(const char *fstype,
+ unsigned int *behavior, sepol_security_id_t * sid)
+{
+ int rc = 0;
+ ocontext_t *c;
+
+ c = policydb->ocontexts[OCON_FSUSE];
+ while (c) {
+ if (strcmp(fstype, c->u.name) == 0)
+ break;
+ c = c->next;
+ }
+
+ if (c) {
+ *behavior = c->v.behavior;
+ if (!c->sid[0]) {
+ rc = sepol_sidtab_context_to_sid(sidtab,
+ &c->context[0],
+ &c->sid[0]);
+ if (rc)
+ goto out;
+ }
+ *sid = c->sid[0];
+ } else {
+ rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+ if (rc) {
+ *behavior = SECURITY_FS_USE_NONE;
+ rc = 0;
+ } else {
+ *behavior = SECURITY_FS_USE_GENFS;
+ }
+ }
+
+ out:
+ return rc;
+}
+
+/* FLASK */
diff --git a/libsepol/src/sidtab.c b/libsepol/src/sidtab.c
new file mode 100644
index 0000000..5bd7999
--- /dev/null
+++ b/libsepol/src/sidtab.c
@@ -0,0 +1,328 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the SID table type.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <sepol/policydb/sidtab.h>
+
+#include <sepol/policydb/flask.h>
+
+#define SIDTAB_HASH(sid) \
+(sid & SIDTAB_HASH_MASK)
+
+#define INIT_SIDTAB_LOCK(s)
+#define SIDTAB_LOCK(s)
+#define SIDTAB_UNLOCK(s)
+
+int sepol_sidtab_init(sidtab_t * s)
+{
+ int i;
+
+ s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE);
+ if (!s->htable)
+ return -ENOMEM;
+ for (i = 0; i < SIDTAB_SIZE; i++)
+ s->htable[i] = (sidtab_ptr_t) NULL;
+ s->nel = 0;
+ s->next_sid = 1;
+ s->shutdown = 0;
+ INIT_SIDTAB_LOCK(s);
+ return 0;
+}
+
+int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid,
+ context_struct_t * context)
+{
+ int hvalue;
+ sidtab_node_t *prev, *cur, *newnode;
+
+ if (!s || !s->htable)
+ return -ENOMEM;
+
+ hvalue = SIDTAB_HASH(sid);
+ prev = NULL;
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur && sid == cur->sid) {
+ errno = EEXIST;
+ return -EEXIST;
+ }
+
+ newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t));
+ if (newnode == NULL)
+ return -ENOMEM;
+ newnode->sid = sid;
+ if (context_cpy(&newnode->context, context)) {
+ free(newnode);
+ return -ENOMEM;
+ }
+
+ if (prev) {
+ newnode->next = prev->next;
+ prev->next = newnode;
+ } else {
+ newnode->next = s->htable[hvalue];
+ s->htable[hvalue] = newnode;
+ }
+
+ s->nel++;
+ if (sid >= s->next_sid)
+ s->next_sid = sid + 1;
+ return 0;
+}
+
+int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid)
+{
+ int hvalue;
+ sidtab_node_t *cur, *last;
+
+ if (!s || !s->htable)
+ return -ENOENT;
+
+ hvalue = SIDTAB_HASH(sid);
+ last = NULL;
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid) {
+ last = cur;
+ cur = cur->next;
+ }
+
+ if (cur == NULL || sid != cur->sid)
+ return -ENOENT;
+
+ if (last == NULL)
+ s->htable[hvalue] = cur->next;
+ else
+ last->next = cur->next;
+
+ context_destroy(&cur->context);
+
+ free(cur);
+ s->nel--;
+ return 0;
+}
+
+context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid)
+{
+ int hvalue;
+ sidtab_node_t *cur;
+
+ if (!s || !s->htable)
+ return NULL;
+
+ hvalue = SIDTAB_HASH(sid);
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid)
+ cur = cur->next;
+
+ if (cur == NULL || sid != cur->sid) {
+ /* Remap invalid SIDs to the unlabeled SID. */
+ sid = SECINITSID_UNLABELED;
+ hvalue = SIDTAB_HASH(sid);
+ cur = s->htable[hvalue];
+ while (cur != NULL && sid > cur->sid)
+ cur = cur->next;
+ if (!cur || sid != cur->sid)
+ return NULL;
+ }
+
+ return &cur->context;
+}
+
+int sepol_sidtab_map(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args)
+{
+ int i, ret;
+ sidtab_node_t *cur;
+
+ if (!s || !s->htable)
+ return 0;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->sid, &cur->context, args);
+ if (ret)
+ return ret;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+void sepol_sidtab_map_remove_on_error(sidtab_t * s,
+ int (*apply) (sepol_security_id_t sid,
+ context_struct_t * context,
+ void *args), void *args)
+{
+ int i, ret;
+ sidtab_node_t *last, *cur, *temp;
+
+ if (!s || !s->htable)
+ return;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ last = NULL;
+ cur = s->htable[i];
+ while (cur != NULL) {
+ ret = apply(cur->sid, &cur->context, args);
+ if (ret) {
+ if (last) {
+ last->next = cur->next;
+ } else {
+ s->htable[i] = cur->next;
+ }
+
+ temp = cur;
+ cur = cur->next;
+ context_destroy(&temp->context);
+ free(temp);
+ s->nel--;
+ } else {
+ last = cur;
+ cur = cur->next;
+ }
+ }
+ }
+
+ return;
+}
+
+static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s,
+ context_struct_t *
+ context)
+{
+ int i;
+ sidtab_node_t *cur;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ if (context_cmp(&cur->context, context))
+ return cur->sid;
+ cur = cur->next;
+ }
+ }
+ return 0;
+}
+
+int sepol_sidtab_context_to_sid(sidtab_t * s,
+ context_struct_t * context,
+ sepol_security_id_t * out_sid)
+{
+ sepol_security_id_t sid;
+ int ret = 0;
+
+ *out_sid = SEPOL_SECSID_NULL;
+
+ sid = sepol_sidtab_search_context(s, context);
+ if (!sid) {
+ SIDTAB_LOCK(s);
+ /* Rescan now that we hold the lock. */
+ sid = sepol_sidtab_search_context(s, context);
+ if (sid)
+ goto unlock_out;
+ /* No SID exists for the context. Allocate a new one. */
+ if (s->next_sid == UINT_MAX || s->shutdown) {
+ ret = -ENOMEM;
+ goto unlock_out;
+ }
+ sid = s->next_sid++;
+ ret = sepol_sidtab_insert(s, sid, context);
+ if (ret)
+ s->next_sid--;
+ unlock_out:
+ SIDTAB_UNLOCK(s);
+ }
+
+ if (ret)
+ return ret;
+
+ *out_sid = sid;
+ return 0;
+}
+
+void sepol_sidtab_hash_eval(sidtab_t * h, char *tag)
+{
+ int i, chain_len, slots_used, max_chain_len;
+ sidtab_node_t *cur;
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = h->htable[i];
+ if (cur) {
+ slots_used++;
+ chain_len = 0;
+ while (cur) {
+ chain_len++;
+ cur = cur->next;
+ }
+
+ if (chain_len > max_chain_len)
+ max_chain_len = chain_len;
+ }
+ }
+
+ printf
+ ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len);
+}
+
+void sepol_sidtab_destroy(sidtab_t * s)
+{
+ int i;
+ sidtab_ptr_t cur, temp;
+
+ if (!s || !s->htable)
+ return;
+
+ for (i = 0; i < SIDTAB_SIZE; i++) {
+ cur = s->htable[i];
+ while (cur != NULL) {
+ temp = cur;
+ cur = cur->next;
+ context_destroy(&temp->context);
+ free(temp);
+ }
+ s->htable[i] = NULL;
+ }
+ free(s->htable);
+ s->htable = NULL;
+ s->nel = 0;
+ s->next_sid = 1;
+}
+
+void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src)
+{
+ SIDTAB_LOCK(src);
+ dst->htable = src->htable;
+ dst->nel = src->nel;
+ dst->next_sid = src->next_sid;
+ dst->shutdown = 0;
+ SIDTAB_UNLOCK(src);
+}
+
+void sepol_sidtab_shutdown(sidtab_t * s)
+{
+ SIDTAB_LOCK(s);
+ s->shutdown = 1;
+ SIDTAB_UNLOCK(s);
+}
+
+/* FLASK */
diff --git a/libsepol/src/symtab.c b/libsepol/src/symtab.c
new file mode 100644
index 0000000..b319c8f
--- /dev/null
+++ b/libsepol/src/symtab.c
@@ -0,0 +1,57 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/* FLASK */
+
+/*
+ * Implementation of the symbol table type.
+ */
+
+#include <string.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/symtab.h>
+
+static unsigned int symhash(hashtab_t h, hashtab_key_t key)
+{
+ char *p, *keyp;
+ size_t size;
+ unsigned int val;
+
+ val = 0;
+ keyp = (char *)key;
+ size = strlen(keyp);
+ for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+ val =
+ (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+ return val & (h->size - 1);
+}
+
+static int symcmp(hashtab_t h
+ __attribute__ ((unused)), hashtab_key_t key1,
+ hashtab_key_t key2)
+{
+ char *keyp1, *keyp2;
+
+ keyp1 = (char *)key1;
+ keyp2 = (char *)key2;
+ return strcmp(keyp1, keyp2);
+}
+
+int symtab_init(symtab_t * s, unsigned int size)
+{
+ s->table = hashtab_create(symhash, symcmp, size);
+ if (!s->table)
+ return -1;
+ s->nprim = 0;
+ return 0;
+}
+
+void symtab_destroy(symtab_t * s)
+{
+ if (!s)
+ return;
+ if (s->table)
+ hashtab_destroy(s->table);
+ return;
+}
+/* FLASK */
diff --git a/libsepol/src/user_internal.h b/libsepol/src/user_internal.h
new file mode 100644
index 0000000..7523b7d
--- /dev/null
+++ b/libsepol/src/user_internal.h
@@ -0,0 +1,20 @@
+#ifndef _SEPOL_USER_INTERNAL_H_
+#define _SEPOL_USER_INTERNAL_H_
+
+#include <sepol/user_record.h>
+#include <sepol/users.h>
+#include "dso.h"
+
+hidden_proto(sepol_user_add_role)
+ hidden_proto(sepol_user_create)
+ hidden_proto(sepol_user_free)
+ hidden_proto(sepol_user_get_mlslevel)
+ hidden_proto(sepol_user_get_mlsrange)
+ hidden_proto(sepol_user_get_roles)
+ hidden_proto(sepol_user_has_role)
+ hidden_proto(sepol_user_key_create)
+ hidden_proto(sepol_user_key_unpack)
+ hidden_proto(sepol_user_set_mlslevel)
+ hidden_proto(sepol_user_set_mlsrange)
+ hidden_proto(sepol_user_set_name)
+#endif
diff --git a/libsepol/src/user_record.c b/libsepol/src/user_record.c
new file mode 100644
index 0000000..c59c54b
--- /dev/null
+++ b/libsepol/src/user_record.c
@@ -0,0 +1,379 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "user_internal.h"
+#include "debug.h"
+
+struct sepol_user {
+ /* This user's name */
+ char *name;
+
+ /* This user's mls level (only required for mls) */
+ char *mls_level;
+
+ /* This user's mls range (only required for mls) */
+ char *mls_range;
+
+ /* The role array */
+ char **roles;
+
+ /* The number of roles */
+ unsigned int num_roles;
+};
+
+struct sepol_user_key {
+ /* This user's name */
+ const char *name;
+};
+
+int sepol_user_key_create(sepol_handle_t * handle,
+ const char *name, sepol_user_key_t ** key_ptr)
+{
+
+ sepol_user_key_t *tmp_key =
+ (sepol_user_key_t *) malloc(sizeof(sepol_user_key_t));
+
+ if (!tmp_key) {
+ ERR(handle, "out of memory, "
+ "could not create selinux user key");
+ return STATUS_ERR;
+ }
+
+ tmp_key->name = name;
+
+ *key_ptr = tmp_key;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_key_create)
+
+void sepol_user_key_unpack(const sepol_user_key_t * key, const char **name)
+{
+
+ *name = key->name;
+}
+
+hidden_def(sepol_user_key_unpack)
+
+int sepol_user_key_extract(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ sepol_user_key_t ** key_ptr)
+{
+
+ if (sepol_user_key_create(handle, user->name, key_ptr) < 0) {
+ ERR(handle, "could not extract key from user %s", user->name);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void sepol_user_key_free(sepol_user_key_t * key)
+{
+ free(key);
+}
+
+int sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key)
+{
+
+ return strcmp(user->name, key->name);
+}
+
+int sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2)
+{
+
+ return strcmp(user->name, user2->name);
+}
+
+/* Name */
+const char *sepol_user_get_name(const sepol_user_t * user)
+{
+
+ return user->name;
+}
+
+int sepol_user_set_name(sepol_handle_t * handle,
+ sepol_user_t * user, const char *name)
+{
+
+ char *tmp_name = strdup(name);
+ if (!tmp_name) {
+ ERR(handle, "out of memory, could not set name");
+ return STATUS_ERR;
+ }
+ free(user->name);
+ user->name = tmp_name;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_name)
+
+/* MLS */
+const char *sepol_user_get_mlslevel(const sepol_user_t * user)
+{
+
+ return user->mls_level;
+}
+
+hidden_def(sepol_user_get_mlslevel)
+
+int sepol_user_set_mlslevel(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_level)
+{
+
+ char *tmp_mls_level = strdup(mls_level);
+ if (!tmp_mls_level) {
+ ERR(handle, "out of memory, "
+ "could not set MLS default level");
+ return STATUS_ERR;
+ }
+ free(user->mls_level);
+ user->mls_level = tmp_mls_level;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlslevel)
+
+const char *sepol_user_get_mlsrange(const sepol_user_t * user)
+{
+
+ return user->mls_range;
+}
+
+hidden_def(sepol_user_get_mlsrange)
+
+int sepol_user_set_mlsrange(sepol_handle_t * handle,
+ sepol_user_t * user, const char *mls_range)
+{
+
+ char *tmp_mls_range = strdup(mls_range);
+ if (!tmp_mls_range) {
+ ERR(handle, "out of memory, "
+ "could not set MLS allowed range");
+ return STATUS_ERR;
+ }
+ free(user->mls_range);
+ user->mls_range = tmp_mls_range;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_set_mlsrange)
+
+/* Roles */
+int sepol_user_get_num_roles(const sepol_user_t * user)
+{
+
+ return user->num_roles;
+}
+
+int sepol_user_add_role(sepol_handle_t * handle,
+ sepol_user_t * user, const char *role)
+{
+
+ char *role_cp;
+ char **roles_realloc;
+
+ if (sepol_user_has_role(user, role))
+ return STATUS_SUCCESS;
+
+ role_cp = strdup(role);
+ roles_realloc = realloc(user->roles,
+ sizeof(char *) * (user->num_roles + 1));
+
+ if (!role_cp || !roles_realloc)
+ goto omem;
+
+ user->num_roles++;
+ user->roles = roles_realloc;
+ user->roles[user->num_roles - 1] = role_cp;
+
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not add role %s", role);
+ free(role_cp);
+ free(roles_realloc);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_user_add_role)
+
+int sepol_user_has_role(const sepol_user_t * user, const char *role)
+{
+
+ unsigned int i;
+
+ for (i = 0; i < user->num_roles; i++)
+ if (!strcmp(user->roles[i], role))
+ return 1;
+ return 0;
+}
+
+hidden_def(sepol_user_has_role)
+
+int sepol_user_set_roles(sepol_handle_t * handle,
+ sepol_user_t * user,
+ const char **roles_arr, unsigned int num_roles)
+{
+
+ unsigned int i;
+ char **tmp_roles = NULL;
+
+ if (num_roles > 0) {
+
+ /* First, make a copy */
+ tmp_roles = (char **)calloc(1, sizeof(char *) * num_roles);
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < num_roles; i++) {
+ tmp_roles[i] = strdup(roles_arr[i]);
+ if (!tmp_roles[i])
+ goto omem;
+ }
+ }
+
+ /* Apply other changes */
+ for (i = 0; i < user->num_roles; i++)
+ free(user->roles[i]);
+ free(user->roles);
+ user->roles = tmp_roles;
+ user->num_roles = num_roles;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not allocate roles array for"
+ "user %s", user->name);
+
+ if (tmp_roles) {
+ for (i = 0; i < num_roles; i++) {
+ if (!tmp_roles[i])
+ break;
+ free(tmp_roles[i]);
+ }
+ }
+ free(tmp_roles);
+ return STATUS_ERR;
+}
+
+int sepol_user_get_roles(sepol_handle_t * handle,
+ const sepol_user_t * user,
+ const char ***roles_arr, unsigned int *num_roles)
+{
+
+ unsigned int i;
+ const char **tmp_roles =
+ (const char **)malloc(sizeof(char *) * user->num_roles);
+ if (!tmp_roles)
+ goto omem;
+
+ for (i = 0; i < user->num_roles; i++)
+ tmp_roles[i] = user->roles[i];
+
+ *roles_arr = tmp_roles;
+ *num_roles = user->num_roles;
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory, could not "
+ "allocate roles array for user %s", user->name);
+ free(tmp_roles);
+ return STATUS_ERR;
+}
+
+hidden_def(sepol_user_get_roles)
+
+void sepol_user_del_role(sepol_user_t * user, const char *role)
+{
+
+ unsigned int i;
+ for (i = 0; i < user->num_roles; i++) {
+ if (!strcmp(user->roles[i], role)) {
+ free(user->roles[i]);
+ user->roles[i] = NULL;
+ user->roles[i] = user->roles[user->num_roles - 1];
+ user->num_roles--;
+ }
+ }
+}
+
+/* Create */
+int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr)
+{
+
+ sepol_user_t *user = (sepol_user_t *) malloc(sizeof(sepol_user_t));
+
+ if (!user) {
+ ERR(handle, "out of memory, "
+ "could not create selinux user record");
+ return STATUS_ERR;
+ }
+
+ user->roles = NULL;
+ user->num_roles = 0;
+ user->name = NULL;
+ user->mls_level = NULL;
+ user->mls_range = NULL;
+
+ *user_ptr = user;
+ return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_user_create)
+
+/* Deep copy clone */
+int sepol_user_clone(sepol_handle_t * handle,
+ const sepol_user_t * user, sepol_user_t ** user_ptr)
+{
+
+ sepol_user_t *new_user = NULL;
+ unsigned int i;
+
+ if (sepol_user_create(handle, &new_user) < 0)
+ goto err;
+
+ if (sepol_user_set_name(handle, new_user, user->name) < 0)
+ goto err;
+
+ for (i = 0; i < user->num_roles; i++) {
+ if (sepol_user_add_role(handle, new_user, user->roles[i]) < 0)
+ goto err;
+ }
+
+ if (user->mls_level &&
+ (sepol_user_set_mlslevel(handle, new_user, user->mls_level) < 0))
+ goto err;
+
+ if (user->mls_range &&
+ (sepol_user_set_mlsrange(handle, new_user, user->mls_range) < 0))
+ goto err;
+
+ *user_ptr = new_user;
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not clone selinux user record");
+ sepol_user_free(new_user);
+ return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_user_free(sepol_user_t * user)
+{
+
+ unsigned int i;
+
+ if (!user)
+ return;
+
+ free(user->name);
+ for (i = 0; i < user->num_roles; i++)
+ free(user->roles[i]);
+ free(user->roles);
+ free(user->mls_level);
+ free(user->mls_range);
+ free(user);
+}
+
+hidden_def(sepol_user_free)
diff --git a/libsepol/src/users.c b/libsepol/src/users.c
new file mode 100644
index 0000000..ce54c2b
--- /dev/null
+++ b/libsepol/src/users.c
@@ -0,0 +1,381 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "private.h"
+#include "debug.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/expand.h>
+#include "user_internal.h"
+#include "mls.h"
+
+static int user_to_record(sepol_handle_t * handle,
+ const policydb_t * policydb,
+ int user_idx, sepol_user_t ** record)
+{
+
+ const char *name = policydb->p_user_val_to_name[user_idx];
+ user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx];
+ ebitmap_t *roles = &(usrdatum->roles.roles);
+ ebitmap_node_t *rnode;
+ unsigned bit;
+
+ sepol_user_t *tmp_record = NULL;
+
+ if (sepol_user_create(handle, &tmp_record) < 0)
+ goto err;
+
+ if (sepol_user_set_name(handle, tmp_record, name) < 0)
+ goto err;
+
+ /* Extract roles */
+ ebitmap_for_each_bit(roles, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit)) {
+ char *role = policydb->p_role_val_to_name[bit];
+ if (sepol_user_add_role(handle, tmp_record, role) < 0)
+ goto err;
+ }
+ }
+
+ /* Extract MLS info */
+ if (policydb->mls) {
+ context_struct_t context;
+ char *str;
+
+ context_init(&context);
+ if (mls_level_cpy(&context.range.level[0],
+ &usrdatum->exp_dfltlevel) < 0) {
+ ERR(handle, "could not copy MLS level");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_level_cpy(&context.range.level[1],
+ &usrdatum->exp_dfltlevel) < 0) {
+ ERR(handle, "could not copy MLS level");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_to_string(handle, policydb, &context, &str) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) {
+ free(str);
+ goto err;
+ }
+ free(str);
+
+ context_init(&context);
+ if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) {
+ ERR(handle, "could not copy MLS range");
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_to_string(handle, policydb, &context, &str) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) {
+ free(str);
+ goto err;
+ }
+ free(str);
+ }
+
+ *record = tmp_record;
+ return STATUS_SUCCESS;
+
+ err:
+ /* FIXME: handle error */
+ sepol_user_free(tmp_record);
+ return STATUS_ERR;
+}
+
+int sepol_user_modify(sepol_handle_t * handle,
+ sepol_policydb_t * p,
+ const sepol_user_key_t * key, const sepol_user_t * user)
+{
+
+ policydb_t *policydb = &p->p;
+
+ /* For user data */
+ const char *cname, *cmls_level, *cmls_range;
+ char *name = NULL;
+
+ const char **roles = NULL;
+ unsigned int num_roles = 0;
+
+ /* Low-level representation */
+ user_datum_t *usrdatum = NULL;
+ role_datum_t *roldatum;
+ unsigned int i;
+
+ context_struct_t context;
+ unsigned bit;
+ int new = 0;
+
+ ebitmap_node_t *rnode;
+
+ /* First, extract all the data */
+ sepol_user_key_unpack(key, &cname);
+
+ cmls_level = sepol_user_get_mlslevel(user);
+ cmls_range = sepol_user_get_mlsrange(user);
+
+ /* Make sure that worked properly */
+ if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0)
+ goto err;
+
+ /* Now, see if a user exists */
+ usrdatum = hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname);
+
+ /* If it does, we will modify it */
+ if (usrdatum) {
+
+ int value_cp = usrdatum->s.value;
+ user_datum_destroy(usrdatum);
+ user_datum_init(usrdatum);
+ usrdatum->s.value = value_cp;
+
+ /* Otherwise, create a new one */
+ } else {
+ usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!usrdatum)
+ goto omem;
+ user_datum_init(usrdatum);
+ new = 1;
+ }
+
+ /* For every role */
+ for (i = 0; i < num_roles; i++) {
+
+ /* Search for the role */
+ roldatum = hashtab_search(policydb->p_roles.table,
+ (const hashtab_key_t)roles[i]);
+ if (!roldatum) {
+ ERR(handle, "undefined role %s for user %s",
+ roles[i], cname);
+ goto err;
+ }
+
+ /* Set the role and every role it dominates */
+ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
+ if (ebitmap_node_get_bit(rnode, bit)) {
+ if (ebitmap_set_bit
+ (&(usrdatum->roles.roles), bit, 1))
+ goto omem;
+ }
+ }
+ }
+
+ /* For MLS systems */
+ if (policydb->mls) {
+
+ /* MLS level */
+ if (cmls_level == NULL) {
+ ERR(handle, "MLS is enabled, but no MLS "
+ "default level was defined for user %s", cname);
+ goto err;
+ }
+
+ context_init(&context);
+ if (mls_from_string(handle, policydb, cmls_level, &context) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_level_cpy(&usrdatum->exp_dfltlevel,
+ &context.range.level[0]) < 0) {
+ ERR(handle, "could not copy MLS level %s", cmls_level);
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+
+ /* MLS range */
+ if (cmls_range == NULL) {
+ ERR(handle, "MLS is enabled, but no MLS"
+ "range was defined for user %s", cname);
+ goto err;
+ }
+
+ context_init(&context);
+ if (mls_from_string(handle, policydb, cmls_range, &context) < 0) {
+ context_destroy(&context);
+ goto err;
+ }
+ if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) {
+ ERR(handle, "could not copy MLS range %s", cmls_range);
+ context_destroy(&context);
+ goto err;
+ }
+ context_destroy(&context);
+ } else if (cmls_level != NULL || cmls_range != NULL) {
+ ERR(handle, "MLS is disabled, but MLS level/range "
+ "was found for user %s", cname);
+ goto err;
+ }
+
+ /* If there are no errors, and this is a new user, add the user to policy */
+ if (new) {
+ void *tmp_ptr;
+
+ /* Ensure reverse lookup array has enough space */
+ tmp_ptr = realloc(policydb->user_val_to_struct,
+ (policydb->p_users.nprim +
+ 1) * sizeof(user_datum_t *));
+ if (!tmp_ptr)
+ goto omem;
+ policydb->user_val_to_struct = tmp_ptr;
+
+ tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS],
+ (policydb->p_users.nprim +
+ 1) * sizeof(char *));
+ if (!tmp_ptr)
+ goto omem;
+ policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
+
+ /* Need to copy the user name */
+ name = strdup(cname);
+ if (!name)
+ goto omem;
+
+ /* Store user */
+ usrdatum->s.value = ++policydb->p_users.nprim;
+ if (hashtab_insert(policydb->p_users.table, name,
+ (hashtab_datum_t) usrdatum) < 0)
+ goto omem;
+
+ /* Set up reverse entry */
+ policydb->p_user_val_to_name[usrdatum->s.value - 1] = name;
+ policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
+ name = NULL;
+
+ /* Expand roles */
+ if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
+ policydb, NULL, NULL)) {
+ ERR(handle, "unable to expand role set");
+ goto err;
+ }
+ }
+
+ free(roles);
+ return STATUS_SUCCESS;
+
+ omem:
+ ERR(handle, "out of memory");
+
+ err:
+ ERR(handle, "could not load %s into policy", name);
+
+ free(name);
+ free(roles);
+ if (new && usrdatum) {
+ role_set_destroy(&usrdatum->roles);
+ free(usrdatum);
+ }
+ return STATUS_ERR;
+}
+
+int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key, int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+
+ const char *cname;
+ sepol_user_key_unpack(key, &cname);
+
+ *response = (hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname) != NULL);
+
+ return STATUS_SUCCESS;
+}
+
+int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)),
+ const sepol_policydb_t * p, unsigned int *response)
+{
+
+ const policydb_t *policydb = &p->p;
+ *response = policydb->p_users.nprim;
+
+ return STATUS_SUCCESS;
+}
+
+int sepol_user_query(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ const sepol_user_key_t * key, sepol_user_t ** response)
+{
+
+ const policydb_t *policydb = &p->p;
+ user_datum_t *usrdatum = NULL;
+
+ const char *cname;
+ sepol_user_key_unpack(key, &cname);
+
+ usrdatum = hashtab_search(policydb->p_users.table,
+ (const hashtab_key_t)cname);
+
+ if (!usrdatum) {
+ *response = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) <
+ 0)
+ goto err;
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not query user %s", cname);
+ return STATUS_ERR;
+}
+
+int sepol_user_iterate(sepol_handle_t * handle,
+ const sepol_policydb_t * p,
+ int (*fn) (const sepol_user_t * user,
+ void *fn_arg), void *arg)
+{
+
+ const policydb_t *policydb = &p->p;
+ unsigned int nusers = policydb->p_users.nprim;
+ sepol_user_t *user = NULL;
+ unsigned int i;
+
+ /* For each user */
+ for (i = 0; i < nusers; i++) {
+
+ int status;
+
+ if (user_to_record(handle, policydb, i, &user) < 0)
+ goto err;
+
+ /* Invoke handler */
+ status = fn(user, arg);
+ if (status < 0)
+ goto err;
+
+ sepol_user_free(user);
+ user = NULL;
+
+ /* Handler requested exit */
+ if (status > 0)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(handle, "could not iterate over users");
+ sepol_user_free(user);
+ return STATUS_ERR;
+}
diff --git a/libsepol/src/util.c b/libsepol/src/util.c
new file mode 100644
index 0000000..ff8f7f2
--- /dev/null
+++ b/libsepol/src/util.c
@@ -0,0 +1,286 @@
+/* Authors: Joshua Brindle <jbrindle@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Copyright (C) 2005-2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/util.h>
+#include <dso.h>
+
+struct val_to_name {
+ unsigned int val;
+ char *name;
+};
+
+/* Add an unsigned integer to a dynamically reallocated array. *cnt
+ * is a reference pointer to the number of values already within array
+ * *a; it will be incremented upon successfully appending i. If *a is
+ * NULL then this function will create a new array (*cnt is reset to
+ * 0). Return 0 on success, -1 on out of memory. */
+int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
+{
+ if (cnt == NULL || a == NULL)
+ return -1;
+
+ /* FIX ME: This is not very elegant! We use an array that we
+ * grow as new uint32_t are added to an array. But rather
+ * than be smart about it, for now we realloc() the array each
+ * time a new uint32_t is added! */
+ if (*a != NULL)
+ *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
+ else { /* empty list */
+
+ *cnt = 0;
+ *a = (uint32_t *) malloc(sizeof(uint32_t));
+ }
+ if (*a == NULL) {
+ return -1;
+ }
+ (*a)[*cnt] = i;
+ (*cnt)++;
+ return 0;
+}
+
+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ struct val_to_name *v = data;
+ perm_datum_t *perdatum;
+
+ perdatum = (perm_datum_t *) datum;
+
+ if (v->val == perdatum->s.value) {
+ v->name = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
+ sepol_access_vector_t av)
+{
+ struct val_to_name v;
+ static char avbuf[1024];
+ class_datum_t *cladatum;
+ char *perm = NULL, *p;
+ unsigned int i;
+ int rc;
+ int avlen = 0, len;
+
+ cladatum = policydbp->class_val_to_struct[tclass - 1];
+ p = avbuf;
+ for (i = 0; i < cladatum->permissions.nprim; i++) {
+ if (av & (1 << i)) {
+ v.val = i + 1;
+ rc = hashtab_map(cladatum->permissions.table,
+ perm_name, &v);
+ if (!rc && cladatum->comdatum) {
+ rc = hashtab_map(cladatum->comdatum->
+ permissions.table, perm_name,
+ &v);
+ }
+ if (rc)
+ perm = v.name;
+ if (perm) {
+ len =
+ snprintf(p, sizeof(avbuf) - avlen, " %s",
+ perm);
+ if (len < 0
+ || (size_t) len >= (sizeof(avbuf) - avlen))
+ return NULL;
+ p += len;
+ avlen += len;
+ }
+ }
+ }
+
+ return avbuf;
+}
+
+#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
+
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
+{
+ uint16_t value;
+ uint16_t low_bit;
+ uint16_t low_value;
+ unsigned int bit;
+ unsigned int in_range = 0;
+ static char xpermsbuf[2048];
+ xpermsbuf[0] = '\0';
+ char *p;
+ int len, xpermslen = 0;
+ p = xpermsbuf;
+
+ if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+ && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+ return NULL;
+
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
+ p += len;
+ xpermslen += len;
+
+ for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
+ if (!xperm_test(bit, xperms->perms))
+ continue;
+
+ if (in_range && next_bit_in_range(bit, xperms->perms)) {
+ /* continue until high value found */
+ continue;
+ } else if (next_bit_in_range(bit, xperms->perms)) {
+ /* low value */
+ low_bit = bit;
+ in_range = 1;
+ continue;
+ }
+
+ if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
+ value = xperms->driver<<8 | bit;
+ low_value = xperms->driver<<8 | low_bit;
+ if (in_range) {
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
+ } else {
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
+ }
+ } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
+ value = bit << 8;
+ low_value = low_bit << 8;
+ if (in_range) {
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
+ } else {
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
+ }
+
+ }
+
+ if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+ return NULL;
+
+ p += len;
+ xpermslen += len;
+ if (in_range)
+ in_range = 0;
+ }
+
+ len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
+ if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+ return NULL;
+
+ return xpermsbuf;
+}
+
+/*
+ * The tokenize and tokenize_str functions may be used to
+ * replace sscanf to read tokens from buffers.
+ */
+
+/* Read a token from a buffer */
+static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
+{
+ char *tmp_buf = *ptr;
+ *str = NULL;
+
+ while (**ptr != '\0') {
+ if (isspace(delim) && isspace(**ptr)) {
+ (*ptr)++;
+ break;
+ } else if (!isspace(delim) && **ptr == delim) {
+ (*ptr)++;
+ break;
+ }
+
+ (*ptr)++;
+ }
+
+ *len = *ptr - tmp_buf;
+ /* If the end of the string has not been reached, this will ensure the
+ * delimiter is not included when returning the token.
+ */
+ if (**ptr != '\0') {
+ (*len)--;
+ }
+
+ *str = strndup(tmp_buf, *len);
+ if (!*str) {
+ return -1;
+ }
+
+ /* Squash spaces if the delimiter is a whitespace character */
+ while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
+ (*ptr)++;
+ }
+
+ return 0;
+}
+
+/*
+ * line_buf - Buffer containing string to tokenize.
+ * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
+ * be tokenized using isspace().
+ * num_args - The number of parameter entries to process.
+ * ... - A 'char **' for each parameter.
+ * returns - The number of items processed.
+ *
+ * This function calls tokenize_str() to do the actual string processing. The
+ * caller is responsible for calling free() on each additional argument. The
+ * function will not tokenize more than num_args and the last argument will
+ * contain the remaining content of line_buf. If the delimiter is any whitespace
+ * character, then all whitespace will be squashed.
+ */
+int hidden tokenize(char *line_buf, char delim, int num_args, ...)
+{
+ char **arg, *buf_p;
+ int rc, items;
+ size_t arg_len = 0;
+ va_list ap;
+
+ buf_p = line_buf;
+
+ /* Process the arguments */
+ va_start(ap, num_args);
+
+ for (items = 0; items < num_args && *buf_p != '\0'; items++) {
+ arg = va_arg(ap, char **);
+
+ /* Save the remainder of the string in arg */
+ if (items == num_args - 1) {
+ *arg = strdup(buf_p);
+ if (*arg == NULL) {
+ goto exit;
+ }
+
+ continue;
+ }
+
+ rc = tokenize_str(delim, arg, &buf_p, &arg_len);
+ if (rc < 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ va_end(ap);
+ return items;
+}
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
new file mode 100644
index 0000000..d87ea61
--- /dev/null
+++ b/libsepol/src/write.c
@@ -0,0 +1,2166 @@
+
+/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org>
+ *
+ * Module writing support
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003-2005 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/flask.h>
+
+#include "debug.h"
+#include "private.h"
+#include "mls.h"
+
+struct policy_data {
+ struct policy_file *fp;
+ struct policydb *p;
+};
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp);
+
+static int ebitmap_write(ebitmap_t * e, struct policy_file *fp)
+{
+ ebitmap_node_t *n;
+ uint32_t buf[32], bit, count;
+ uint64_t map;
+ size_t items;
+
+ buf[0] = cpu_to_le32(MAPSIZE);
+ buf[1] = cpu_to_le32(e->highbit);
+
+ count = 0;
+ for (n = e->node; n; n = n->next)
+ count++;
+ buf[2] = cpu_to_le32(count);
+
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+
+ for (n = e->node; n; n = n->next) {
+ bit = cpu_to_le32(n->startbit);
+ items = put_entry(&bit, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ map = cpu_to_le64(n->map);
+ items = put_entry(&map, sizeof(uint64_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+/* Ordering of datums in the original avtab format in the policy file. */
+static uint16_t spec_order[] = {
+ AVTAB_ALLOWED,
+ AVTAB_AUDITDENY,
+ AVTAB_AUDITALLOW,
+ AVTAB_TRANSITION,
+ AVTAB_CHANGE,
+ AVTAB_MEMBER
+};
+
+static int avtab_write_item(policydb_t * p,
+ avtab_ptr_t cur, struct policy_file *fp,
+ unsigned merge, unsigned commit, uint32_t * nel)
+{
+ avtab_ptr_t node;
+ uint8_t buf8;
+ uint16_t buf16[4];
+ uint32_t buf32[10], lookup, val;
+ size_t items, items2;
+ unsigned set;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+ unsigned int i;
+
+ if (oldvers) {
+ /* Generate the old avtab format.
+ Requires merging similar entries if uncond avtab. */
+ if (merge) {
+ if (cur->merged)
+ return POLICYDB_SUCCESS; /* already merged by prior merge */
+ }
+
+ items = 1; /* item 0 is used for the item count */
+ val = cur->key.source_type;
+ buf32[items++] = cpu_to_le32(val);
+ val = cur->key.target_type;
+ buf32[items++] = cpu_to_le32(val);
+ val = cur->key.target_class;
+ buf32[items++] = cpu_to_le32(val);
+
+ val = cur->key.specified & ~AVTAB_ENABLED;
+ if (cur->key.specified & AVTAB_ENABLED)
+ val |= AVTAB_ENABLED_OLD;
+ set = 1;
+
+ if (merge) {
+ /* Merge specifier values for all similar (av or type)
+ entries that have the same key. */
+ if (val & AVTAB_AV)
+ lookup = AVTAB_AV;
+ else if (val & AVTAB_TYPE)
+ lookup = AVTAB_TYPE;
+ else
+ return POLICYDB_ERROR;
+ for (node = avtab_search_node_next(cur, lookup);
+ node;
+ node = avtab_search_node_next(node, lookup)) {
+ val |= (node->key.specified & ~AVTAB_ENABLED);
+ set++;
+ if (node->key.specified & AVTAB_ENABLED)
+ val |= AVTAB_ENABLED_OLD;
+ }
+ }
+
+ if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+ ERR(fp->handle, "null entry");
+ return POLICYDB_ERROR;
+ }
+ if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
+ ERR(fp->handle, "entry has both access "
+ "vectors and types");
+ return POLICYDB_ERROR;
+ }
+
+ buf32[items++] = cpu_to_le32(val);
+
+ if (merge) {
+ /* Include datums for all similar (av or type)
+ entries that have the same key. */
+ for (i = 0;
+ i < (sizeof(spec_order) / sizeof(spec_order[0]));
+ i++) {
+ if (val & spec_order[i]) {
+ if (cur->key.specified & spec_order[i])
+ node = cur;
+ else {
+ node =
+ avtab_search_node_next(cur,
+ spec_order
+ [i]);
+ if (nel)
+ (*nel)--; /* one less node */
+ }
+
+ if (!node) {
+ ERR(fp->handle, "missing node");
+ return POLICYDB_ERROR;
+ }
+ buf32[items++] =
+ cpu_to_le32(node->datum.data);
+ set--;
+ node->merged = 1;
+ }
+ }
+ } else {
+ buf32[items++] = cpu_to_le32(cur->datum.data);
+ cur->merged = 1;
+ set--;
+ }
+
+ if (set) {
+ ERR(fp->handle, "data count wrong");
+ return POLICYDB_ERROR;
+ }
+
+ buf32[0] = cpu_to_le32(items - 1);
+
+ if (commit) {
+ /* Commit this item to the policy file. */
+ items2 = put_entry(buf32, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+ }
+
+ /* Generate the new avtab format. */
+ buf16[0] = cpu_to_le16(cur->key.source_type);
+ buf16[1] = cpu_to_le16(cur->key.target_type);
+ buf16[2] = cpu_to_le16(cur->key.target_class);
+ buf16[3] = cpu_to_le16(cur->key.specified);
+ items = put_entry(buf16, sizeof(uint16_t), 4, fp);
+ if (items != 4)
+ return POLICYDB_ERROR;
+ if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+ (cur->key.specified & AVTAB_XPERMS)) {
+ ERR(fp->handle, "policy version %u does not support ioctl extended"
+ "permissions rules and one was specified", p->policyvers);
+ return POLICYDB_ERROR;
+ }
+
+ if (p->target_platform != SEPOL_TARGET_SELINUX &&
+ (cur->key.specified & AVTAB_XPERMS)) {
+ ERR(fp->handle, "Target platform %s does not support ioctl "
+ "extended permissions rules and one was specified",
+ policydb_target_strings[p->target_platform]);
+ return POLICYDB_ERROR;
+ }
+
+ if (cur->key.specified & AVTAB_XPERMS) {
+ buf8 = cur->datum.xperms->specified;
+ items = put_entry(&buf8, sizeof(uint8_t),1,fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ buf8 = cur->datum.xperms->driver;
+ items = put_entry(&buf8, sizeof(uint8_t),1,fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
+ buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
+ items = put_entry(buf32, sizeof(uint32_t),8,fp);
+ if (items != 8)
+ return POLICYDB_ERROR;
+ } else {
+ buf32[0] = cpu_to_le32(cur->datum.data);
+ items = put_entry(buf32, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static inline void avtab_reset_merged(avtab_t * a)
+{
+ unsigned int i;
+ avtab_ptr_t cur;
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next)
+ cur->merged = 0;
+ }
+}
+
+static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
+{
+ unsigned int i;
+ int rc;
+ avtab_t expa;
+ avtab_ptr_t cur;
+ uint32_t nel;
+ size_t items;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+
+ if (oldvers) {
+ /* Old avtab format.
+ First, we need to expand attributes. Then, we need to
+ merge similar entries, so we need to track merged nodes
+ and compute the final nel. */
+ if (avtab_init(&expa))
+ return POLICYDB_ERROR;
+ if (expand_avtab(p, a, &expa)) {
+ rc = -1;
+ goto out;
+ }
+ a = &expa;
+ avtab_reset_merged(a);
+ nel = a->nel;
+ } else {
+ /* New avtab format. nel is good to go. */
+ nel = cpu_to_le32(a->nel);
+ items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ /* If old format, compute final nel.
+ If new format, write out the items. */
+ if (avtab_write_item(p, cur, fp, 1, !oldvers, &nel)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ }
+
+ if (oldvers) {
+ /* Old avtab format.
+ Write the computed nel value, then write the items. */
+ nel = cpu_to_le32(nel);
+ items = put_entry(&nel, sizeof(uint32_t), 1, fp);
+ if (items != 1) {
+ rc = -1;
+ goto out;
+ }
+ avtab_reset_merged(a);
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
+ rc = -1;
+ goto out;
+ }
+ }
+ }
+ }
+
+ rc = 0;
+ out:
+ if (oldvers)
+ avtab_destroy(&expa);
+ return rc;
+}
+
+/*
+ * Write a semantic MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_semantic_level_helper(mls_semantic_level_t * l,
+ struct policy_file *fp)
+{
+ uint32_t buf[2], ncat = 0;
+ size_t items;
+ mls_semantic_cat_t *cat;
+
+ for (cat = l->cat; cat; cat = cat->next)
+ ncat++;
+
+ buf[0] = cpu_to_le32(l->sens);
+ buf[1] = cpu_to_le32(ncat);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+
+ for (cat = l->cat; cat; cat = cat->next) {
+ buf[0] = cpu_to_le32(cat->low);
+ buf[1] = cpu_to_le32(cat->high);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Read a semantic MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_semantic_range_helper(mls_semantic_range_t * r,
+ struct policy_file *fp)
+{
+ int rc;
+
+ rc = mls_write_semantic_level_helper(&r->level[0], fp);
+ if (rc)
+ return rc;
+
+ rc = mls_write_semantic_level_helper(&r->level[1], fp);
+
+ return rc;
+}
+
+/*
+ * Write a MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_level(mls_level_t * l, struct policy_file *fp)
+{
+ uint32_t sens;
+ size_t items;
+
+ sens = cpu_to_le32(l->sens);
+ items = put_entry(&sens, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&l->cat, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_range_helper(mls_range_t * r, struct policy_file *fp)
+{
+ uint32_t buf[3];
+ size_t items, items2;
+ int eq;
+
+ eq = mls_level_eq(&r->level[1], &r->level[0]);
+
+ items = 1; /* item 0 is used for the item count */
+ buf[items++] = cpu_to_le32(r->level[0].sens);
+ if (!eq)
+ buf[items++] = cpu_to_le32(r->level[1].sens);
+ buf[0] = cpu_to_le32(items - 1);
+
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&r->level[0].cat, fp))
+ return POLICYDB_ERROR;
+ if (!eq)
+ if (ebitmap_write(&r->level[1].cat, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ level_datum_t *levdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ levdatum = (level_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(levdatum->isalias);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (mls_write_level(levdatum->level, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ cat_datum_t *catdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ catdatum = (cat_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(catdatum->s.value);
+ buf[items++] = cpu_to_le32(catdatum->isalias);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_trans_write(policydb_t *p, struct policy_file *fp)
+{
+ role_trans_t *r = p->role_tr;
+ role_trans_t *tr;
+ uint32_t buf[3];
+ size_t nel, items;
+ int new_roletr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_ROLETRANS);
+ int warning_issued = 0;
+
+ nel = 0;
+ for (tr = r; tr; tr = tr->next)
+ if(new_roletr || tr->tclass == SECCLASS_PROCESS)
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (tr = r; tr; tr = tr->next) {
+ if (!new_roletr && tr->tclass != SECCLASS_PROCESS) {
+ if (!warning_issued)
+ WARN(fp->handle, "Discarding role_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warning_issued = 1;
+ continue;
+ }
+ buf[0] = cpu_to_le32(tr->role);
+ buf[1] = cpu_to_le32(tr->type);
+ buf[2] = cpu_to_le32(tr->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+ if (new_roletr) {
+ buf[0] = cpu_to_le32(tr->tclass);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_allow_write(role_allow_t * r, struct policy_file *fp)
+{
+ role_allow_t *ra;
+ uint32_t buf[2];
+ size_t nel, items;
+
+ nel = 0;
+ for (ra = r; ra; ra = ra->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ra = r; ra; ra = ra->next) {
+ buf[0] = cpu_to_le32(ra->role);
+ buf[1] = cpu_to_le32(ra->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_write(filename_trans_t * r, struct policy_file *fp)
+{
+ filename_trans_t *ft;
+ uint32_t buf[4];
+ size_t nel, items, len;
+
+ nel = 0;
+ for (ft = r; ft; ft = ft->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ft = r; ft; ft = ft->next) {
+ len = strlen(ft->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ items = put_entry(ft->name, sizeof(char), len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(ft->stype);
+ buf[1] = cpu_to_le32(ft->ttype);
+ buf[2] = cpu_to_le32(ft->tclass);
+ buf[3] = cpu_to_le32(ft->otype);
+ items = put_entry(buf, sizeof(uint32_t), 4, fp);
+ if (items != 4)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_set_write(role_set_t * x, struct policy_file *fp)
+{
+ size_t items;
+ uint32_t buf[1];
+
+ if (ebitmap_write(&x->roles, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(x->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int type_set_write(type_set_t * x, struct policy_file *fp)
+{
+ size_t items;
+ uint32_t buf[1];
+
+ if (ebitmap_write(&x->types, fp))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&x->negset, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(x->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ cond_bool_datum_t *booldatum;
+ uint32_t buf[3], len;
+ unsigned int items, items2;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ booldatum = (cond_bool_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(booldatum->s.value);
+ buf[items++] = cpu_to_le32(booldatum->state);
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+ buf[0] = cpu_to_le32(booldatum->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * cond_write_cond_av_list doesn't write out the av_list nodes.
+ * Instead it writes out the key/value pairs from the avtab. This
+ * is necessary because there is no way to uniquely identifying rules
+ * in the avtab so it is not possible to associate individual rules
+ * in the avtab with a conditional without saving them as part of
+ * the conditional. This means that the avtab with the conditional
+ * rules will not be saved but will be rebuilt on policy load.
+ */
+static int cond_write_av_list(policydb_t * p,
+ cond_av_list_t * list, struct policy_file *fp)
+{
+ uint32_t buf[4];
+ cond_av_list_t *cur_list, *new_list = NULL;
+ avtab_t expa;
+ uint32_t len, items;
+ unsigned int oldvers = (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_AVTAB);
+ int rc = -1;
+
+ if (oldvers) {
+ if (avtab_init(&expa))
+ return POLICYDB_ERROR;
+ if (expand_cond_av_list(p, list, &new_list, &expa))
+ goto out;
+ list = new_list;
+ }
+
+ len = 0;
+ for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+ if (cur_list->node->parse_context)
+ len++;
+ }
+
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ goto out;
+
+ if (len == 0) {
+ rc = 0;
+ goto out;
+ }
+
+ for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+ if (cur_list->node->parse_context)
+ if (avtab_write_item(p, cur_list->node, fp, 0, 1, NULL))
+ goto out;
+ }
+
+ rc = 0;
+ out:
+ if (oldvers) {
+ cond_av_list_destroy(new_list);
+ avtab_destroy(&expa);
+ }
+
+ return rc;
+}
+
+static int cond_write_node(policydb_t * p,
+ cond_node_t * node, struct policy_file *fp)
+{
+ cond_expr_t *cur_expr;
+ uint32_t buf[2];
+ uint32_t items, items2, len;
+
+ buf[0] = cpu_to_le32(node->cur_state);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ /* expr */
+ len = 0;
+ for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
+ len++;
+
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
+ items = 0;
+ buf[items++] = cpu_to_le32(cur_expr->expr_type);
+ buf[items++] = cpu_to_le32(cur_expr->bool);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (cond_write_av_list(p, node->true_list, fp) != 0)
+ return POLICYDB_ERROR;
+ if (cond_write_av_list(p, node->false_list, fp) != 0)
+ return POLICYDB_ERROR;
+ } else {
+ if (avrule_write_list(node->avtrue_list, fp))
+ return POLICYDB_ERROR;
+ if (avrule_write_list(node->avfalse_list, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
+ buf[0] = cpu_to_le32(node->flags);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int cond_write_list(policydb_t * p, cond_list_t * list,
+ struct policy_file *fp)
+{
+ cond_node_t *cur;
+ uint32_t len, items;
+ uint32_t buf[1];
+
+ len = 0;
+ for (cur = list; cur != NULL; cur = cur->next)
+ len++;
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (cur = list; cur != NULL; cur = cur->next) {
+ if (cond_write_node(p, cur, fp) != 0)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * Write a security context structure
+ * to a policydb binary representation file.
+ */
+static int context_write(struct policydb *p, context_struct_t * c,
+ struct policy_file *fp)
+{
+ uint32_t buf[32];
+ size_t items, items2;
+
+ items = 0;
+ buf[items++] = cpu_to_le32(c->user);
+ buf[items++] = cpu_to_le32(c->role);
+ buf[items++] = cpu_to_le32(c->type);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_BASE))
+ if (mls_write_range_helper(&c->range, fp))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+/*
+ * The following *_write functions are used to
+ * write the symbol data to a policy database
+ * binary representation file.
+ */
+
+static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ perm_datum_t *perdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ perdatum = (perm_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(perdatum->s.value);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ common_datum_t *comdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+
+ comdatum = (common_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(comdatum->s.value);
+ buf[items++] = cpu_to_le32(comdatum->permissions.nprim);
+ buf[items++] = cpu_to_le32(comdatum->permissions.table->nel);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (hashtab_map(comdatum->permissions.table, perm_write, pd))
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int write_cons_helper(policydb_t * p,
+ constraint_node_t * node, int allowxtarget,
+ struct policy_file *fp)
+{
+ constraint_node_t *c;
+ constraint_expr_t *e;
+ uint32_t buf[3], nexpr;
+ int items;
+
+ for (c = node; c; c = c->next) {
+ nexpr = 0;
+ for (e = c->expr; e; e = e->next) {
+ nexpr++;
+ }
+ buf[0] = cpu_to_le32(c->permissions);
+ buf[1] = cpu_to_le32(nexpr);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ for (e = c->expr; e; e = e->next) {
+ items = 0;
+ buf[0] = cpu_to_le32(e->expr_type);
+ buf[1] = cpu_to_le32(e->attr);
+ buf[2] = cpu_to_le32(e->op);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+
+ switch (e->expr_type) {
+ case CEXPR_NAMES:
+ if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&e->names, fp)) {
+ return POLICYDB_ERROR;
+ }
+ if ((p->policy_type != POLICY_KERN &&
+ type_set_write(e->type_names, fp)) ||
+ (p->policy_type == POLICY_KERN &&
+ (p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) &&
+ type_set_write(e->type_names, fp))) {
+ return POLICYDB_ERROR;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ class_datum_t *cladatum;
+ constraint_node_t *c;
+ uint32_t buf[32], ncons;
+ size_t items, items2, len, len2;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ cladatum = (class_datum_t *) datum;
+
+ len = strlen(key);
+ if (cladatum->comkey)
+ len2 = strlen(cladatum->comkey);
+ else
+ len2 = 0;
+
+ ncons = 0;
+ for (c = cladatum->constraints; c; c = c->next) {
+ ncons++;
+ }
+
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(len2);
+ buf[items++] = cpu_to_le32(cladatum->s.value);
+ buf[items++] = cpu_to_le32(cladatum->permissions.nprim);
+ if (cladatum->permissions.table)
+ buf[items++] = cpu_to_le32(cladatum->permissions.table->nel);
+ else
+ buf[items++] = 0;
+ buf[items++] = cpu_to_le32(ncons);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (cladatum->comkey) {
+ items = put_entry(cladatum->comkey, 1, len2, fp);
+ if (items != len2)
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(cladatum->permissions.table, perm_write, pd))
+ return POLICYDB_ERROR;
+
+ if (write_cons_helper(p, cladatum->constraints, 0, fp))
+ return POLICYDB_ERROR;
+
+ if ((p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
+ || (p->policy_type == POLICY_BASE
+ && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
+ /* write out the validatetrans rule */
+ ncons = 0;
+ for (c = cladatum->validatetrans; c; c = c->next) {
+ ncons++;
+ }
+ buf[0] = cpu_to_le32(ncons);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (write_cons_helper(p, cladatum->validatetrans, 1, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) ||
+ (p->policy_type == POLICY_BASE &&
+ p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) {
+ buf[0] = cpu_to_le32(cladatum->default_user);
+ buf[1] = cpu_to_le32(cladatum->default_role);
+ buf[2] = cpu_to_le32(cladatum->default_range);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
+ (p->policy_type == POLICY_BASE &&
+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
+ buf[0] = cpu_to_le32(cladatum->default_type);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ role_datum_t *role;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ role = (role_datum_t *) datum;
+
+ /*
+ * Role attributes are redundant for policy.X, skip them
+ * when writing the roles symbol table. They are also skipped
+ * when pp is downgraded.
+ *
+ * Their numbers would be deducted in policydb_write().
+ */
+ if ((role->flavor == ROLE_ATTRIB) &&
+ ((p->policy_type == POLICY_KERN) ||
+ (p->policy_type != POLICY_KERN &&
+ p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
+ return POLICYDB_SUCCESS;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(role->s.value);
+ if (policydb_has_boundary_feature(p))
+ buf[items++] = cpu_to_le32(role->bounds);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&role->dominates, fp))
+ return POLICYDB_ERROR;
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&role->types.types, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (type_set_write(&role->types, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type != POLICY_KERN &&
+ p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
+ buf[0] = cpu_to_le32(role->flavor);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ if (ebitmap_write(&role->roles, fp))
+ return POLICYDB_ERROR;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ type_datum_t *typdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ typdatum = (type_datum_t *) datum;
+
+ /*
+ * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
+ * does not support to load entries of attribute, so we skip to write it.
+ */
+ if (p->policy_type == POLICY_KERN
+ && p->policyvers < POLICYDB_VERSION_BOUNDARY
+ && typdatum->flavor == TYPE_ATTRIB)
+ return POLICYDB_SUCCESS;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(typdatum->s.value);
+ if (policydb_has_boundary_feature(p)) {
+ uint32_t properties = 0;
+
+ if (p->policy_type != POLICY_KERN
+ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
+ buf[items++] = cpu_to_le32(typdatum->primary);
+ }
+
+ if (typdatum->primary)
+ properties |= TYPEDATUM_PROPERTY_PRIMARY;
+
+ if (typdatum->flavor == TYPE_ATTRIB) {
+ properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+ } else if (typdatum->flavor == TYPE_ALIAS
+ && p->policy_type != POLICY_KERN)
+ properties |= TYPEDATUM_PROPERTY_ALIAS;
+
+ if (typdatum->flags & TYPE_FLAGS_PERMISSIVE
+ && p->policy_type != POLICY_KERN)
+ properties |= TYPEDATUM_PROPERTY_PERMISSIVE;
+
+ buf[items++] = cpu_to_le32(properties);
+ buf[items++] = cpu_to_le32(typdatum->bounds);
+ } else {
+ buf[items++] = cpu_to_le32(typdatum->primary);
+
+ if (p->policy_type != POLICY_KERN) {
+ buf[items++] = cpu_to_le32(typdatum->flavor);
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+ buf[items++] = cpu_to_le32(typdatum->flags);
+ else if (typdatum->flags & TYPE_FLAGS_PERMISSIVE)
+ WARN(fp->handle, "Warning! Module policy "
+ "version %d cannot support permissive "
+ "types, but one was defined",
+ p->policyvers);
+ }
+ }
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type != POLICY_KERN) {
+ if (ebitmap_write(&typdatum->types, fp))
+ return POLICYDB_ERROR;
+ }
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ return POLICYDB_SUCCESS;
+}
+
+static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ user_datum_t *usrdatum;
+ uint32_t buf[32];
+ size_t items, items2, len;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ struct policydb *p = pd->p;
+
+ usrdatum = (user_datum_t *) datum;
+
+ len = strlen(key);
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ buf[items++] = cpu_to_le32(usrdatum->s.value);
+ if (policydb_has_boundary_feature(p))
+ buf[items++] = cpu_to_le32(usrdatum->bounds);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ items = put_entry(key, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&usrdatum->roles.roles, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (role_set_write(&usrdatum->roles, fp))
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_MOD)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_BASE)) {
+ if (mls_write_range_helper(&usrdatum->exp_range, fp))
+ return POLICYDB_ERROR;
+ if (mls_write_level(&usrdatum->exp_dfltlevel, fp))
+ return POLICYDB_ERROR;
+ } else if ((p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_MOD)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
+ && p->policy_type == POLICY_BASE)) {
+ if (mls_write_semantic_range_helper(&usrdatum->range, fp))
+ return -1;
+ if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp))
+ return -1;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+ void *datap) = {
+common_write, class_write, role_write, type_write, user_write,
+ cond_write_bool, sens_write, cat_write,};
+
+static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p,
+ struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, items, len;
+ uint32_t buf[32];
+ ocontext_t *c;
+ for (i = 0; i < info->ocon_num; i++) {
+ nel = 0;
+ for (c = p->ocontexts[i]; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = p->ocontexts[i]; c; c = c->next) {
+ switch (i) {
+ case OCON_XEN_ISID:
+ buf[0] = cpu_to_le32(c->sid[0]);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_PIRQ:
+ buf[0] = cpu_to_le32(c->u.pirq);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_IOPORT:
+ buf[0] = c->u.ioport.low_ioport;
+ buf[1] = c->u.ioport.high_ioport;
+ for (j = 0; j < 2; j++)
+ buf[j] = cpu_to_le32(buf[j]);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_IOMEM:
+ if (p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE) {
+ uint64_t b64[2];
+ b64[0] = c->u.iomem.low_iomem;
+ b64[1] = c->u.iomem.high_iomem;
+ for (j = 0; j < 2; j++)
+ b64[j] = cpu_to_le64(b64[j]);
+ items = put_entry(b64, sizeof(uint64_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ } else {
+ if (c->u.iomem.high_iomem > 0xFFFFFFFFULL) {
+ ERR(fp->handle, "policy version %d"
+ " cannot represent IOMEM addresses over 16TB",
+ p->policyvers);
+ return POLICYDB_ERROR;
+ }
+
+ buf[0] = c->u.iomem.low_iomem;
+ buf[1] = c->u.iomem.high_iomem;
+ for (j = 0; j < 2; j++)
+ buf[j] = cpu_to_le32(buf[j]);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_PCIDEVICE:
+ buf[0] = cpu_to_le32(c->u.device);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_XEN_DEVICETREE:
+ len = strlen(c->u.name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write_selinux(struct policydb_compat_info *info,
+ policydb_t *p, struct policy_file *fp)
+{
+ unsigned int i, j;
+ size_t nel, items, len;
+ uint32_t buf[32];
+ ocontext_t *c;
+ for (i = 0; i < info->ocon_num; i++) {
+ nel = 0;
+ for (c = p->ocontexts[i]; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = p->ocontexts[i]; c; c = c->next) {
+ switch (i) {
+ case OCON_ISID:
+ buf[0] = cpu_to_le32(c->sid[0]);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_FS:
+ case OCON_NETIF:
+ len = strlen(c->u.name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[1], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_PORT:
+ buf[0] = c->u.port.protocol;
+ buf[1] = c->u.port.low_port;
+ buf[2] = c->u.port.high_port;
+ for (j = 0; j < 3; j++) {
+ buf[j] = cpu_to_le32(buf[j]);
+ }
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_NODE:
+ buf[0] = c->u.node.addr; /* network order */
+ buf[1] = c->u.node.mask; /* network order */
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_FSUSE:
+ buf[0] = cpu_to_le32(c->v.behavior);
+ len = strlen(c->u.name);
+ buf[1] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ case OCON_NODE6:
+ for (j = 0; j < 4; j++)
+ buf[j] = c->u.node6.addr[j]; /* network order */
+ for (j = 0; j < 4; j++)
+ buf[j + 4] = c->u.node6.mask[j]; /* network order */
+ items = put_entry(buf, sizeof(uint32_t), 8, fp);
+ if (items != 8)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ break;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int ocontext_write(struct policydb_compat_info *info, policydb_t * p,
+ struct policy_file *fp)
+{
+ int rc = POLICYDB_ERROR;
+ switch (p->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ rc = ocontext_write_selinux(info, p, fp);
+ break;
+ case SEPOL_TARGET_XEN:
+ rc = ocontext_write_xen(info, p, fp);
+ break;
+ }
+ return rc;
+}
+
+static int genfs_write(policydb_t * p, struct policy_file *fp)
+{
+ genfs_t *genfs;
+ ocontext_t *c;
+ size_t nel = 0, items, len;
+ uint32_t buf[32];
+
+ for (genfs = p->genfs; genfs; genfs = genfs->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (genfs = p->genfs; genfs; genfs = genfs->next) {
+ len = strlen(genfs->fstype);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(genfs->fstype, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ nel = 0;
+ for (c = genfs->head; c; c = c->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (c = genfs->head; c; c = c->next) {
+ len = strlen(c->u.name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(c->u.name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ buf[0] = cpu_to_le32(c->v.sclass);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ if (context_write(p, &c->context[0], fp))
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int range_write(policydb_t * p, struct policy_file *fp)
+{
+ size_t nel, items;
+ struct range_trans *rt;
+ uint32_t buf[2];
+ int new_rangetr = (p->policy_type == POLICY_KERN &&
+ p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+ int warning_issued = 0;
+
+ nel = 0;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ /* all range_transitions are written for the new format, only
+ process related range_transitions are written for the old
+ format, so count accordingly */
+ if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
+ nel++;
+ }
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (rt = p->range_tr; rt; rt = rt->next) {
+ if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
+ if (!warning_issued)
+ WARN(fp->handle, "Discarding range_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warning_issued = 1;
+ continue;
+ }
+ buf[0] = cpu_to_le32(rt->source_type);
+ buf[1] = cpu_to_le32(rt->target_type);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (new_rangetr) {
+ buf[0] = cpu_to_le32(rt->target_class);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ if (mls_write_range_helper(&rt->target_range, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+/************** module writing functions below **************/
+
+static int avrule_write(avrule_t * avrule, struct policy_file *fp)
+{
+ size_t items, items2;
+ uint32_t buf[32], len;
+ class_perm_node_t *cur;
+
+ if (avrule->specified & AVRULE_XPERMS) {
+ ERR(fp->handle, "module policy does not support extended"
+ " permissions rules and one was specified");
+ return POLICYDB_ERROR;
+ }
+
+ items = 0;
+ buf[items++] = cpu_to_le32(avrule->specified);
+ buf[items++] = cpu_to_le32(avrule->flags);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&avrule->stypes, fp))
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&avrule->ttypes, fp))
+ return POLICYDB_ERROR;
+
+ cur = avrule->perms;
+ len = 0;
+ while (cur) {
+ len++;
+ cur = cur->next;
+ }
+ items = 0;
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+ cur = avrule->perms;
+ while (cur) {
+ items = 0;
+ buf[items++] = cpu_to_le32(cur->tclass);
+ buf[items++] = cpu_to_le32(cur->data);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items2 != items)
+ return POLICYDB_ERROR;
+
+ cur = cur->next;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_write_list(avrule_t * avrules, struct policy_file *fp)
+{
+ uint32_t buf[32], len;
+ avrule_t *avrule;
+
+ avrule = avrules;
+ len = 0;
+ while (avrule) {
+ len++;
+ avrule = avrule->next;
+ }
+
+ buf[0] = cpu_to_le32(len);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1)
+ return POLICYDB_ERROR;
+
+ avrule = avrules;
+ while (avrule) {
+ if (avrule_write(avrule, fp))
+ return POLICYDB_ERROR;
+ avrule = avrule->next;
+ }
+
+ return POLICYDB_SUCCESS;
+}
+
+static int only_process(ebitmap_t *in)
+{
+ unsigned int i;
+ ebitmap_node_t *node;
+
+ ebitmap_for_each_bit(in, node, i) {
+ if (ebitmap_node_get_bit(node, i) &&
+ i != SECCLASS_PROCESS - 1)
+ return 0;
+ }
+ return 1;
+}
+
+static int role_trans_rule_write(policydb_t *p, role_trans_rule_t * t,
+ struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ role_trans_rule_t *tr;
+ int warned = 0;
+ int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS;
+
+ for (tr = t; tr; tr = tr->next)
+ if (new_role || only_process(&tr->classes))
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (tr = t; tr; tr = tr->next) {
+ if (!new_role && !only_process(&tr->classes)) {
+ if (!warned)
+ WARN(fp->handle, "Discarding role_transition "
+ "rules for security classes other than "
+ "\"process\"");
+ warned = 1;
+ continue;
+ }
+ if (role_set_write(&tr->roles, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&tr->types, fp))
+ return POLICYDB_ERROR;
+ if (new_role)
+ if (ebitmap_write(&tr->classes, fp))
+ return POLICYDB_ERROR;
+ buf[0] = cpu_to_le32(tr->new_role);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ role_allow_rule_t *ra;
+
+ for (ra = r; ra; ra = ra->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (ra = r; ra; ra = ra->next) {
+ if (role_set_write(&ra->roles, fp))
+ return POLICYDB_ERROR;
+ if (role_set_write(&ra->new_roles, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[2], len;
+ filename_trans_rule_t *ftr;
+
+ for (ftr = t; ftr; ftr = ftr->next)
+ nel++;
+
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ for (ftr = t; ftr; ftr = ftr->next) {
+ len = strlen(ftr->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ items = put_entry(ftr->name, sizeof(char), len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ if (type_set_write(&ftr->stypes, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&ftr->ttypes, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(ftr->tclass);
+ buf[1] = cpu_to_le32(ftr->otype);
+
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int range_trans_rule_write(range_trans_rule_t * t,
+ struct policy_file *fp)
+{
+ int nel = 0;
+ size_t items;
+ uint32_t buf[1];
+ range_trans_rule_t *rt;
+
+ for (rt = t; rt; rt = rt->next)
+ nel++;
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ for (rt = t; rt; rt = rt->next) {
+ if (type_set_write(&rt->stypes, fp))
+ return POLICYDB_ERROR;
+ if (type_set_write(&rt->ttypes, fp))
+ return POLICYDB_ERROR;
+ if (ebitmap_write(&rt->tclasses, fp))
+ return POLICYDB_ERROR;
+ if (mls_write_semantic_range_helper(&rt->trange, fp))
+ return POLICYDB_ERROR;
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int scope_index_write(scope_index_t * scope_index,
+ unsigned int num_scope_syms,
+ struct policy_file *fp)
+{
+ unsigned int i;
+ uint32_t buf[1];
+ for (i = 0; i < num_scope_syms; i++) {
+ if (ebitmap_write(scope_index->scope + i, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ buf[0] = cpu_to_le32(scope_index->class_perms_len);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ for (i = 0; i < scope_index->class_perms_len; i++) {
+ if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms,
+ policydb_t * p, struct policy_file *fp)
+{
+ struct policy_data pd;
+ uint32_t buf[2];
+ int i;
+ buf[0] = cpu_to_le32(decl->decl_id);
+ buf[1] = cpu_to_le32(decl->enabled);
+ if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+ return POLICYDB_ERROR;
+ }
+ if (cond_write_list(p, decl->cond_list, fp) == -1 ||
+ avrule_write_list(decl->avrules, fp) == -1 ||
+ role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 ||
+ role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
+ filename_trans_rule_write(decl->filename_trans_rules, fp))
+ return POLICYDB_ERROR;
+
+ if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
+ range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 ||
+ scope_index_write(&decl->declared, num_scope_syms, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+ pd.fp = fp;
+ pd.p = p;
+ for (i = 0; i < num_scope_syms; i++) {
+ buf[0] = cpu_to_le32(decl->symtab[i].nprim);
+ buf[1] = cpu_to_le32(decl->symtab[i].table->nel);
+ if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) {
+ return POLICYDB_ERROR;
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int avrule_block_write(avrule_block_t * block, int num_scope_syms,
+ policydb_t * p, struct policy_file *fp)
+{
+ /* first write a count of the total number of blocks */
+ uint32_t buf[1], num_blocks = 0;
+ avrule_block_t *cur;
+ for (cur = block; cur != NULL; cur = cur->next) {
+ num_blocks++;
+ }
+ buf[0] = cpu_to_le32(num_blocks);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+
+ /* now write each block */
+ for (cur = block; cur != NULL; cur = cur->next) {
+ uint32_t num_decls = 0;
+ avrule_decl_t *decl;
+ /* write a count of number of branches */
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ num_decls++;
+ }
+ buf[0] = cpu_to_le32(num_decls);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
+ if (avrule_decl_write(decl, num_scope_syms, p, fp) ==
+ -1) {
+ return POLICYDB_ERROR;
+ }
+ }
+ }
+ return POLICYDB_SUCCESS;
+}
+
+static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
+{
+ scope_datum_t *scope = (scope_datum_t *) datum;
+ struct policy_data *pd = ptr;
+ struct policy_file *fp = pd->fp;
+ uint32_t static_buf[32], *dyn_buf = NULL, *buf;
+ size_t key_len = strlen(key);
+ unsigned int items = 2 + scope->decl_ids_len, i;
+ int rc;
+
+ buf = static_buf;
+ if (items >= (sizeof(static_buf) / 4)) {
+ /* too many things required, so dynamically create a
+ * buffer. this would have been easier with C99's
+ * dynamic arrays... */
+ rc = POLICYDB_ERROR;
+ dyn_buf = malloc(items * sizeof(*dyn_buf));
+ if (!dyn_buf)
+ goto err;
+ buf = dyn_buf;
+ }
+ buf[0] = cpu_to_le32(key_len);
+
+ rc = POLICYDB_ERROR;
+ if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
+ put_entry(key, 1, key_len, fp) != key_len)
+ goto err;
+ buf[0] = cpu_to_le32(scope->scope);
+ buf[1] = cpu_to_le32(scope->decl_ids_len);
+
+ for (i = 0; i < scope->decl_ids_len; i++)
+ buf[2 + i] = cpu_to_le32(scope->decl_ids[i]);
+
+ rc = POLICYDB_ERROR;
+ if (put_entry(buf, sizeof(*buf), items, fp) != items)
+ goto err;
+ rc = POLICYDB_SUCCESS;
+err:
+ free(dyn_buf);
+ return rc;
+}
+
+static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
+ hashtab_datum_t datum, void *args)
+{
+ type_datum_t *typdatum = datum;
+ uint32_t *p_nel = args;
+
+ if (typdatum->flavor == TYPE_ATTRIB) {
+ /* uncount attribute from total number of types */
+ (*p_nel)--;
+ }
+ return 0;
+}
+
+static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
+ hashtab_datum_t datum, void *args)
+{
+ role_datum_t *role = datum;
+ uint32_t *p_nel = args;
+
+ if (role->flavor == ROLE_ATTRIB) {
+ /* uncount attribute from total number of roles */
+ (*p_nel)--;
+ }
+ return 0;
+}
+
+/*
+ * Write the configuration data in a policy database
+ * structure to a policy database binary representation
+ * file.
+ */
+int policydb_write(policydb_t * p, struct policy_file *fp)
+{
+ unsigned int i, num_syms;
+ uint32_t buf[32], config;
+ size_t items, items2, len;
+ struct policydb_compat_info *info;
+ struct policy_data pd;
+ const char *policydb_str;
+
+ if (p->unsupported_format)
+ return POLICYDB_UNSUPPORTED;
+
+ pd.fp = fp;
+ pd.p = p;
+
+ config = 0;
+ if (p->mls) {
+ if ((p->policyvers < POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
+ p->policy_type == POLICY_MOD)) {
+ ERR(fp->handle, "policy version %d cannot support MLS",
+ p->policyvers);
+ return POLICYDB_ERROR;
+ }
+ config |= POLICYDB_CONFIG_MLS;
+ }
+
+ config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown);
+
+ /* Write the magic number and string identifiers. */
+ items = 0;
+ if (p->policy_type == POLICY_KERN) {
+ buf[items++] = cpu_to_le32(POLICYDB_MAGIC);
+ len = strlen(policydb_target_strings[p->target_platform]);
+ policydb_str = policydb_target_strings[p->target_platform];
+ } else {
+ buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC);
+ len = strlen(POLICYDB_MOD_STRING);
+ policydb_str = POLICYDB_MOD_STRING;
+ }
+ buf[items++] = cpu_to_le32(len);
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+ items = put_entry(policydb_str, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ /* Write the version, config, and table sizes. */
+ items = 0;
+ info = policydb_lookup_compat(p->policyvers, p->policy_type,
+ p->target_platform);
+ if (!info) {
+ ERR(fp->handle, "compatibility lookup failed for policy "
+ "version %d", p->policyvers);
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type != POLICY_KERN) {
+ buf[items++] = cpu_to_le32(p->policy_type);
+ }
+ buf[items++] = cpu_to_le32(p->policyvers);
+ buf[items++] = cpu_to_le32(config);
+ buf[items++] = cpu_to_le32(info->sym_num);
+ buf[items++] = cpu_to_le32(info->ocon_num);
+
+ items2 = put_entry(buf, sizeof(uint32_t), items, fp);
+ if (items != items2)
+ return POLICYDB_ERROR;
+
+ if (p->policy_type == POLICY_MOD) {
+ /* Write module name and version */
+ len = strlen(p->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(p->name, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ len = strlen(p->version);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+ items = put_entry(p->version, 1, len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_KERN) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_BASE) ||
+ (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
+ p->policy_type == POLICY_MOD)) {
+ if (ebitmap_write(&p->policycaps, fp) == -1)
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policyvers < POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ ebitmap_node_t *tnode;
+
+ ebitmap_for_each_bit(&p->permissive_map, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ WARN(fp->handle, "Warning! Policy version %d cannot "
+ "support permissive types, but some were defined",
+ p->policyvers);
+ break;
+ }
+ }
+ }
+
+ if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+ p->policy_type == POLICY_KERN) {
+ if (ebitmap_write(&p->permissive_map, fp) == -1)
+ return POLICYDB_ERROR;
+ }
+
+ num_syms = info->sym_num;
+ for (i = 0; i < num_syms; i++) {
+ buf[0] = cpu_to_le32(p->symtab[i].nprim);
+ buf[1] = p->symtab[i].table->nel;
+
+ /*
+ * A special case when writing type/attribute symbol table.
+ * The kernel policy version less than 24 does not support
+ * to load entries of attribute, so we have to re-calculate
+ * the actual number of types except for attributes.
+ */
+ if (i == SYM_TYPES &&
+ p->policyvers < POLICYDB_VERSION_BOUNDARY &&
+ p->policy_type == POLICY_KERN) {
+ hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]);
+ }
+
+ /*
+ * Another special case when writing role/attribute symbol
+ * table, role attributes are redundant for policy.X, or
+ * when the pp's version is not big enough. So deduct
+ * their numbers from p_roles.table->nel.
+ */
+ if ((i == SYM_ROLES) &&
+ ((p->policy_type == POLICY_KERN) ||
+ (p->policy_type != POLICY_KERN &&
+ p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
+ (void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]);
+
+ buf[1] = cpu_to_le32(buf[1]);
+ items = put_entry(buf, sizeof(uint32_t), 2, fp);
+ if (items != 2)
+ return POLICYDB_ERROR;
+ if (hashtab_map(p->symtab[i].table, write_f[i], &pd))
+ return POLICYDB_ERROR;
+ }
+
+ if (p->policy_type == POLICY_KERN) {
+ if (avtab_write(p, &p->te_avtab, fp))
+ return POLICYDB_ERROR;
+ if (p->policyvers < POLICYDB_VERSION_BOOL) {
+ if (p->p_bools.nprim)
+ WARN(fp->handle, "Discarding "
+ "booleans and conditional rules");
+ } else {
+ if (cond_write_list(p, p->cond_list, fp))
+ return POLICYDB_ERROR;
+ }
+ if (role_trans_write(p, fp))
+ return POLICYDB_ERROR;
+ if (role_allow_write(p->role_allow, fp))
+ return POLICYDB_ERROR;
+ if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
+ if (filename_trans_write(p->filename_trans, fp))
+ return POLICYDB_ERROR;
+ } else {
+ if (p->filename_trans)
+ WARN(fp->handle, "Discarding filename type transition rules");
+ }
+ } else {
+ if (avrule_block_write(p->global, num_syms, p, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ for (i = 0; i < num_syms; i++) {
+ buf[0] = cpu_to_le32(p->scope[i].table->nel);
+ if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
+ return POLICYDB_ERROR;
+ }
+ if (hashtab_map(p->scope[i].table, scope_write, &pd))
+ return POLICYDB_ERROR;
+ }
+ }
+
+ if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) {
+ return POLICYDB_ERROR;
+ }
+
+ if ((p->policyvers >= POLICYDB_VERSION_MLS
+ && p->policy_type == POLICY_KERN)
+ || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
+ && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS
+ && p->policy_type == POLICY_BASE)) {
+ if (range_write(p, fp)) {
+ return POLICYDB_ERROR;
+ }
+ }
+
+ if (p->policy_type == POLICY_KERN
+ && p->policyvers >= POLICYDB_VERSION_AVTAB) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_write(&p->type_attr_map[i], fp) == -1)
+ return POLICYDB_ERROR;
+ }
+ }
+
+ return POLICYDB_SUCCESS;
+}
diff --git a/libsepol/tests/Makefile b/libsepol/tests/Makefile
new file mode 100644
index 0000000..dd7bd33
--- /dev/null
+++ b/libsepol/tests/Makefile
@@ -0,0 +1,54 @@
+M4 ?= m4
+MKDIR ?= mkdir
+EXE ?= libsepol-tests
+
+CFLAGS += -g3 -gdwarf-2 -o0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter -Werror
+
+# Statically link libsepol on the assumption that we are going to
+# be testing internal functions.
+LIBSEPOL := ../src/libsepol.a
+
+# In order to load source policies we need to link in the checkpolicy/checkmodule parser and util code.
+# This is less than ideal, but it makes the tests easier to maintain by allowing source policies
+# to be loaded directly.
+CHECKPOLICY := ../../checkpolicy/
+CPPFLAGS += -I../include/ -I$(CHECKPOLICY)
+
+# test program object files
+objs := $(patsubst %.c,%.o,$(wildcard *.c))
+parserobjs := $(CHECKPOLICY)queue.o $(CHECKPOLICY)y.tab.o \
+ $(CHECKPOLICY)parse_util.o $(CHECKPOLICY)lex.yy.o \
+ $(CHECKPOLICY)policy_define.o $(CHECKPOLICY)module_compiler.o
+
+# test policy pieces
+m4support := $(wildcard policies/support/*.spt)
+testsuites := $(wildcard policies/test-*)
+policysrc := $(foreach path,$(testsuites),$(wildcard $(path)/*.conf))
+stdpol := $(addsuffix .std,$(policysrc))
+mlspol := $(addsuffix .mls,$(policysrc))
+policies := $(stdpol) $(mlspol)
+
+all: $(EXE) $(policies)
+policies: $(policies)
+
+$(EXE): $(objs) $(parserobjs) $(LIBSEPOL)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(objs) $(parserobjs) -lfl -lcunit -lcurses $(LIBSEPOL) -o $@
+
+%.conf.std: $(m4support) %.conf
+ $(M4) $(M4PARAMS) $^ > $@
+
+%.conf.mls: $(m4support) %.conf
+ $(M4) $(M4PARAMS) -D enable_mls $^ > $@
+
+clean:
+ rm -f $(objs) $(EXE)
+ rm -f $(policies)
+ rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo
+
+
+test: $(EXE) $(policies)
+ $(MKDIR) -p policies/test-downgrade
+ ../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi
+ ./$(EXE)
+
+.PHONY: all policies clean test
diff --git a/libsepol/tests/debug.c b/libsepol/tests/debug.c
new file mode 100644
index 0000000..90aa6e0
--- /dev/null
+++ b/libsepol/tests/debug.c
@@ -0,0 +1,69 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include "debug.h"
+
+#include <stdlib.h>
+
+void print_ebitmap(ebitmap_t * bitmap, FILE * fp)
+{
+ uint32_t i;
+ for (i = 0; i < bitmap->highbit; i++) {
+ fprintf(fp, "%d", ebitmap_get_bit(bitmap, i));
+ }
+ fprintf(fp, "\n");
+}
+
+/* stolen from dispol.c */
+void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
+{
+
+ cond_expr_t *cur;
+ for (cur = exp; cur != NULL; cur = cur->next) {
+ switch (cur->expr_type) {
+ case COND_BOOL:
+ fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]);
+ break;
+ case COND_NOT:
+ fprintf(fp, "! ");
+ break;
+ case COND_OR:
+ fprintf(fp, "|| ");
+ break;
+ case COND_AND:
+ fprintf(fp, "&& ");
+ break;
+ case COND_XOR:
+ fprintf(fp, "^ ");
+ break;
+ case COND_EQ:
+ fprintf(fp, "== ");
+ break;
+ case COND_NEQ:
+ fprintf(fp, "!= ");
+ break;
+ default:
+ fprintf(fp, "error! (%d)", cur->expr_type);
+ break;
+ }
+ }
+}
diff --git a/libsepol/tests/debug.h b/libsepol/tests/debug.h
new file mode 100644
index 0000000..c25ebd4
--- /dev/null
+++ b/libsepol/tests/debug.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+extern void print_ebitmap(ebitmap_t * bitmap, FILE * fp);
+extern void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp);
diff --git a/libsepol/tests/helpers.c b/libsepol/tests/helpers.c
new file mode 100644
index 0000000..542e467
--- /dev/null
+++ b/libsepol/tests/helpers.c
@@ -0,0 +1,81 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This has helper functions that are common between tests */
+
+#include "helpers.h"
+#include "parse_util.h"
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+#include <stdlib.h>
+#include <limits.h>
+
+int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name)
+{
+ char filename[PATH_MAX];
+
+ if (mls) {
+ if (snprintf(filename, PATH_MAX, "policies/%s/%s.mls", test_name, policy_name) < 0) {
+ return -1;
+ }
+ } else {
+ if (snprintf(filename, PATH_MAX, "policies/%s/%s.std", test_name, policy_name) < 0) {
+ return -1;
+ }
+ }
+
+ if (policydb_init(p)) {
+ fprintf(stderr, "Out of memory");
+ return -1;
+ }
+
+ p->policy_type = policy_type;
+ p->mls = mls;
+
+ if (read_source_policy(p, filename, test_name)) {
+ fprintf(stderr, "failed to read policy %s\n", filename);
+ policydb_destroy(p);
+ return -1;
+ }
+
+ return 0;
+}
+
+avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym)
+{
+ scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symtab].table, sym);
+
+ if (scope == NULL) {
+ return NULL;
+ }
+ if (scope->scope != SCOPE_DECL) {
+ return NULL;
+ }
+ if (scope->decl_ids_len != 1) {
+ return NULL;
+ }
+
+ return p->decl_val_to_struct[scope->decl_ids[0] - 1];
+}
diff --git a/libsepol/tests/helpers.h b/libsepol/tests/helpers.h
new file mode 100644
index 0000000..418ee95
--- /dev/null
+++ b/libsepol/tests/helpers.h
@@ -0,0 +1,59 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+/* helper functions */
+
+/* Load a source policy into p. policydb_init will called within this function.
+ *
+ * Example: test_load_policy(p, POLICY_BASE, 1, "foo", "base.conf") will load the
+ * policy "policies/foo/mls/base.conf" into p.
+ *
+ * Arguments:
+ * p policydb_t into which the policy will be read. This should be
+ * malloc'd but not passed to policydb_init.
+ * policy_type Type of policy expected - POLICY_BASE or POLICY_MOD.
+ * mls Boolean value indicating whether an mls policy is expected.
+ * test_name Name of the test which will be the name of the directory in
+ * which the policies are stored.
+ * policy_name Name of the policy in the directory.
+ *
+ * Returns:
+ * 0 success
+ * -1 error - the policydb will be destroyed but not freed.
+ */
+extern int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name);
+
+/* Find an avrule_decl_t by a unique symbol. If the symbol is declared in more
+ * than one decl an error is returned.
+ *
+ * Returns:
+ * decl success
+ * NULL error (including more than one declaration)
+ */
+extern avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym);
+
+#endif
diff --git a/libsepol/tests/libsepol-tests.c b/libsepol/tests/libsepol-tests.c
new file mode 100644
index 0000000..9302f72
--- /dev/null
+++ b/libsepol/tests/libsepol-tests.c
@@ -0,0 +1,118 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-cond.h"
+#include "test-linker.h"
+#include "test-expander.h"
+#include "test-deps.h"
+#include "test-downgrade.h"
+
+#include <CUnit/Basic.h>
+#include <CUnit/Console.h>
+#include <CUnit/TestDB.h>
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+int mls;
+
+#define DECLARE_SUITE(name) \
+ suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \
+ if (NULL == suite) { \
+ CU_cleanup_registry(); \
+ return CU_get_error(); } \
+ if (name##_add_tests(suite)) { \
+ CU_cleanup_registry(); \
+ return CU_get_error(); }
+
+static void usage(char *progname)
+{
+ printf("usage: %s [options]\n", progname);
+ printf("options:\n");
+ printf("\t-v, --verbose\t\t\tverbose output\n");
+ printf("\t-i, --interactive\t\tinteractive console\n");
+}
+
+static int do_tests(int interactive, int verbose)
+{
+ CU_pSuite suite = NULL;
+
+ if (CUE_SUCCESS != CU_initialize_registry())
+ return CU_get_error();
+
+ DECLARE_SUITE(cond);
+ DECLARE_SUITE(linker);
+ DECLARE_SUITE(expander);
+ DECLARE_SUITE(deps);
+ DECLARE_SUITE(downgrade);
+
+ if (verbose)
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ else
+ CU_basic_set_mode(CU_BRM_NORMAL);
+
+ if (interactive)
+ CU_console_run_tests();
+ else
+ CU_basic_run_tests();
+ CU_cleanup_registry();
+ return CU_get_error();
+
+}
+
+int main(int argc, char **argv)
+{
+ int i, verbose = 1, interactive = 0;
+
+ struct option opts[] = {
+ {"verbose", 0, NULL, 'v'},
+ {"interactive", 0, NULL, 'i'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while ((i = getopt_long(argc, argv, "vi", opts, NULL)) != -1) {
+ switch (i) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'h':
+ default:{
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ }
+
+ /* first do the non-mls tests */
+ mls = 0;
+ if (do_tests(interactive, verbose))
+ return -1;
+
+ /* then with mls */
+ mls = 1;
+ if (do_tests(interactive, verbose))
+ return -1;
+
+ return 0;
+}
diff --git a/libsepol/tests/policies/support/misc_macros.spt b/libsepol/tests/policies/support/misc_macros.spt
new file mode 100644
index 0000000..5fadd0f
--- /dev/null
+++ b/libsepol/tests/policies/support/misc_macros.spt
@@ -0,0 +1,23 @@
+
+########################################
+#
+# Helper macros
+#
+
+########################################
+#
+# gen_user(username, prefix, role_set, mls_defaultlevel, mls_range, [mcs_categories])
+#
+define(`gen_user',`dnl
+ifdef(`users_extra',`dnl
+ifelse(`$2',,,`user $1 prefix $2;')
+',`dnl
+user $1 roles { $3 }`'ifdef(`enable_mls', ` level $4 range $5')`'ifdef(`enable_mcs',` level s0 range s0`'ifelse(`$6',,,` - s0:$6')');
+')dnl
+')
+
+########################################
+#
+# gen_context(context,mls_sensitivity,[mcs_categories])
+#
+define(`gen_context',`$1`'ifdef(`enable_mls',`:$2')`'ifdef(`enable_mcs',`:s0`'ifelse(`$3',,,`:$3')')') dnl
diff --git a/libsepol/tests/policies/test-cond/refpolicy-base.conf b/libsepol/tests/policies/test-cond/refpolicy-base.conf
new file mode 100644
index 0000000..1c1ef9a
--- /dev/null
+++ b/libsepol/tests/policies/test-cond/refpolicy-base.conf
@@ -0,0 +1,1940 @@
+class security
+class process
+class system
+class capability
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+class sem
+class msg
+class msgq
+class shm
+class ipc
+class passwd # userspace
+class drawable # userspace
+class window # userspace
+class gc # userspace
+class font # userspace
+class colormap # userspace
+class property # userspace
+class cursor # userspace
+class xclient # userspace
+class xinput # userspace
+class xserver # userspace
+class xextension # userspace
+class pax
+class netlink_route_socket
+class netlink_firewall_socket
+class netlink_tcpdiag_socket
+class netlink_nflog_socket
+class netlink_xfrm_socket
+class netlink_selinux_socket
+class netlink_audit_socket
+class netlink_ip6fw_socket
+class netlink_dnrt_socket
+class dbus # userspace
+class nscd # userspace
+class association
+class netlink_kobject_uevent_socket
+sid kernel
+sid security
+sid unlabeled
+sid fs
+sid file
+sid file_labels
+sid init
+sid any_socket
+sid port
+sid netif
+sid netmsg
+sid node
+sid igmp_packet
+sid icmp_socket
+sid tcp_socket
+sid sysctl_modprobe
+sid sysctl
+sid sysctl_fs
+sid sysctl_kernel
+sid sysctl_net
+sid sysctl_net_unix
+sid sysctl_vm
+sid sysctl_dev
+sid kmod
+sid policy
+sid scmp_packet
+sid devnull
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+common socket
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+ execmod
+}
+class lnk_file
+inherits file
+class chr_file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+ execmod
+}
+class blk_file
+inherits file
+class sock_file
+inherits file
+class fifo_file
+inherits file
+class fd
+{
+ use
+}
+class socket
+inherits socket
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+ node_bind
+ name_connect
+}
+class udp_socket
+inherits socket
+{
+ node_bind
+}
+class rawip_socket
+inherits socket
+{
+ node_bind
+}
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+class netlink_socket
+inherits socket
+class packet_socket
+inherits socket
+class key_socket
+inherits socket
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+class unix_dgram_socket
+inherits socket
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+ getattr
+ setexec
+ setfscreate
+ noatsecure
+ siginh
+ setrlimit
+ rlimitinh
+ dyntransition
+ setcurrent
+ execmem
+ execstack
+ execheap
+}
+class ipc
+inherits ipc
+class sem
+inherits ipc
+class msgq
+inherits ipc
+{
+ enqueue
+}
+class msg
+{
+ send
+ receive
+}
+class shm
+inherits ipc
+{
+ lock
+}
+class security
+{
+ compute_av
+ compute_create
+ compute_member
+ check_context
+ load_policy
+ compute_relabel
+ compute_user
+ setenforce # was avc_toggle in system class
+ setbool
+ setsecparam
+ setcheckreqprot
+}
+class system
+{
+ ipc_info
+ syslog_read
+ syslog_mod
+ syslog_console
+}
+class capability
+{
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+ audit_write
+ audit_control
+}
+class passwd
+{
+ passwd # change another user passwd
+ chfn # change another user finger info
+ chsh # change another user shell
+ rootok # pam_rootok check (skip auth)
+ crontab # crontab on another user
+}
+class drawable
+{
+ create
+ destroy
+ draw
+ copy
+ getattr
+}
+class gc
+{
+ create
+ free
+ getattr
+ setattr
+}
+class window
+{
+ addchild
+ create
+ destroy
+ map
+ unmap
+ chstack
+ chproplist
+ chprop
+ listprop
+ getattr
+ setattr
+ setfocus
+ move
+ chselection
+ chparent
+ ctrllife
+ enumerate
+ transparent
+ mousemotion
+ clientcomevent
+ inputevent
+ drawevent
+ windowchangeevent
+ windowchangerequest
+ serverchangeevent
+ extensionevent
+}
+class font
+{
+ load
+ free
+ getattr
+ use
+}
+class colormap
+{
+ create
+ free
+ install
+ uninstall
+ list
+ read
+ store
+ getattr
+ setattr
+}
+class property
+{
+ create
+ free
+ read
+ write
+}
+class cursor
+{
+ create
+ createglyph
+ free
+ assign
+ setattr
+}
+class xclient
+{
+ kill
+}
+class xinput
+{
+ lookup
+ getattr
+ setattr
+ setfocus
+ warppointer
+ activegrab
+ passivegrab
+ ungrab
+ bell
+ mousemotion
+ relabelinput
+}
+class xserver
+{
+ screensaver
+ gethostlist
+ sethostlist
+ getfontpath
+ setfontpath
+ getattr
+ grab
+ ungrab
+}
+class xextension
+{
+ query
+ use
+}
+class pax
+{
+ pageexec # Paging based non-executable pages
+ emutramp # Emulate trampolines
+ mprotect # Restrict mprotect()
+ randmmap # Randomize mmap() base
+ randexec # Randomize ET_EXEC base
+ segmexec # Segmentation based non-executable pages
+}
+class netlink_route_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_firewall_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_tcpdiag_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_nflog_socket
+inherits socket
+class netlink_xfrm_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_selinux_socket
+inherits socket
+class netlink_audit_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+ nlmsg_relay
+ nlmsg_readpriv
+}
+class netlink_ip6fw_socket
+inherits socket
+{
+ nlmsg_read
+ nlmsg_write
+}
+class netlink_dnrt_socket
+inherits socket
+class dbus
+{
+ acquire_svc
+ send_msg
+}
+class nscd
+{
+ getpwd
+ getgrp
+ gethost
+ getstat
+ admin
+ shmempwd
+ shmemgrp
+ shmemhost
+}
+class association
+{
+ sendto
+ recvfrom
+ setcontext
+}
+class netlink_kobject_uevent_socket
+inherits socket
+sensitivity s0;
+dominance { s0 }
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+category c24; category c25; category c26; category c27;
+category c28; category c29; category c30; category c31;
+category c32; category c33; category c34; category c35;
+category c36; category c37; category c38; category c39;
+category c40; category c41; category c42; category c43;
+category c44; category c45; category c46; category c47;
+category c48; category c49; category c50; category c51;
+category c52; category c53; category c54; category c55;
+category c56; category c57; category c58; category c59;
+category c60; category c61; category c62; category c63;
+category c64; category c65; category c66; category c67;
+category c68; category c69; category c70; category c71;
+category c72; category c73; category c74; category c75;
+category c76; category c77; category c78; category c79;
+category c80; category c81; category c82; category c83;
+category c84; category c85; category c86; category c87;
+category c88; category c89; category c90; category c91;
+category c92; category c93; category c94; category c95;
+category c96; category c97; category c98; category c99;
+category c100; category c101; category c102; category c103;
+category c104; category c105; category c106; category c107;
+category c108; category c109; category c110; category c111;
+category c112; category c113; category c114; category c115;
+category c116; category c117; category c118; category c119;
+category c120; category c121; category c122; category c123;
+category c124; category c125; category c126; category c127;
+category c128; category c129; category c130; category c131;
+category c132; category c133; category c134; category c135;
+category c136; category c137; category c138; category c139;
+category c140; category c141; category c142; category c143;
+category c144; category c145; category c146; category c147;
+category c148; category c149; category c150; category c151;
+category c152; category c153; category c154; category c155;
+category c156; category c157; category c158; category c159;
+category c160; category c161; category c162; category c163;
+category c164; category c165; category c166; category c167;
+category c168; category c169; category c170; category c171;
+category c172; category c173; category c174; category c175;
+category c176; category c177; category c178; category c179;
+category c180; category c181; category c182; category c183;
+category c184; category c185; category c186; category c187;
+category c188; category c189; category c190; category c191;
+category c192; category c193; category c194; category c195;
+category c196; category c197; category c198; category c199;
+category c200; category c201; category c202; category c203;
+category c204; category c205; category c206; category c207;
+category c208; category c209; category c210; category c211;
+category c212; category c213; category c214; category c215;
+category c216; category c217; category c218; category c219;
+category c220; category c221; category c222; category c223;
+category c224; category c225; category c226; category c227;
+category c228; category c229; category c230; category c231;
+category c232; category c233; category c234; category c235;
+category c236; category c237; category c238; category c239;
+category c240; category c241; category c242; category c243;
+category c244; category c245; category c246; category c247;
+category c248; category c249; category c250; category c251;
+category c252; category c253; category c254; category c255;
+level s0:c0.c255;
+mlsconstrain file { write setattr append unlink link rename
+ ioctl lock execute relabelfrom } (h1 dom h2);
+mlsconstrain file { create relabelto } ((h1 dom h2) and (l2 eq h2));
+mlsconstrain file { read } ((h1 dom h2) or ( t2 == domain ) or ( t1 == mlsfileread ));
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { relabelfrom }
+ ( h1 dom h2 );
+mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { create relabelto }
+ (( h1 dom h2 ) and ( l2 eq h2 ));
+mlsconstrain process { ptrace } ( h1 dom h2 );
+mlsconstrain process { sigkill sigstop } ( h1 dom h2 ) or
+ ( t1 == mcskillall );
+mlsconstrain xextension query ( t1 == mlsfileread );
+attribute netif_type;
+attribute node_type;
+attribute port_type;
+attribute reserved_port_type;
+attribute device_node;
+attribute memory_raw_read;
+attribute memory_raw_write;
+attribute domain;
+attribute unconfined_domain_type;
+attribute set_curr_context;
+attribute entry_type;
+attribute privfd;
+attribute can_change_process_identity;
+attribute can_change_process_role;
+attribute can_change_object_identity;
+attribute can_system_change;
+attribute process_user_target;
+attribute cron_source_domain;
+attribute cron_job_domain;
+attribute process_uncond_exempt; # add userhelperdomain to this one
+attribute file_type;
+attribute lockfile;
+attribute mountpoint;
+attribute pidfile;
+attribute polydir;
+attribute usercanread;
+attribute polyparent;
+attribute polymember;
+attribute security_file_type;
+attribute tmpfile;
+attribute tmpfsfile;
+attribute filesystem_type;
+attribute noxattrfs;
+attribute can_load_kernmodule;
+attribute can_receive_kernel_messages;
+attribute kern_unconfined;
+attribute proc_type;
+attribute sysctl_type;
+attribute mcskillall;
+attribute mlsfileread;
+attribute mlsfilereadtoclr;
+attribute mlsfilewrite;
+attribute mlsfilewritetoclr;
+attribute mlsfileupgrade;
+attribute mlsfiledowngrade;
+attribute mlsnetread;
+attribute mlsnetreadtoclr;
+attribute mlsnetwrite;
+attribute mlsnetwritetoclr;
+attribute mlsnetupgrade;
+attribute mlsnetdowngrade;
+attribute mlsnetrecvall;
+attribute mlsipcread;
+attribute mlsipcreadtoclr;
+attribute mlsipcwrite;
+attribute mlsipcwritetoclr;
+attribute mlsprocread;
+attribute mlsprocreadtoclr;
+attribute mlsprocwrite;
+attribute mlsprocwritetoclr;
+attribute mlsprocsetsl;
+attribute mlsxwinread;
+attribute mlsxwinreadtoclr;
+attribute mlsxwinwrite;
+attribute mlsxwinwritetoclr;
+attribute mlsxwinreadproperty;
+attribute mlsxwinwriteproperty;
+attribute mlsxwinreadcolormap;
+attribute mlsxwinwritecolormap;
+attribute mlsxwinwritexinput;
+attribute mlstrustedobject;
+attribute privrangetrans;
+attribute mlsrangetrans;
+attribute can_load_policy;
+attribute can_setenforce;
+attribute can_setsecparam;
+attribute ttynode;
+attribute ptynode;
+attribute server_ptynode;
+attribute serial_device;
+type bin_t;
+type sbin_t;
+type ls_exec_t;
+type shell_exec_t;
+type chroot_exec_t;
+type ppp_device_t;
+type tun_tap_device_t;
+type port_t, port_type;
+type reserved_port_t, port_type, reserved_port_type;
+type afs_bos_port_t, port_type;
+type afs_fs_port_t, port_type;
+type afs_ka_port_t, port_type;
+type afs_pt_port_t, port_type;
+type afs_vl_port_t, port_type;
+type amanda_port_t, port_type;
+type amavisd_recv_port_t, port_type;
+type amavisd_send_port_t, port_type;
+type asterisk_port_t, port_type;
+type auth_port_t, port_type;
+type bgp_port_t, port_type;
+type biff_port_t, port_type, reserved_port_type;
+type clamd_port_t, port_type;
+type clockspeed_port_t, port_type;
+type comsat_port_t, port_type;
+type cvs_port_t, port_type;
+type dcc_port_t, port_type;
+type dbskkd_port_t, port_type;
+type dhcpc_port_t, port_type;
+type dhcpd_port_t, port_type;
+type dict_port_t, port_type;
+type distccd_port_t, port_type;
+type dns_port_t, port_type;
+type fingerd_port_t, port_type;
+type ftp_data_port_t, port_type;
+type ftp_port_t, port_type;
+type gatekeeper_port_t, port_type;
+type giftd_port_t, port_type;
+type gopher_port_t, port_type;
+type http_cache_port_t, port_type;
+type http_port_t, port_type;
+type howl_port_t, port_type;
+type hplip_port_t, port_type;
+type i18n_input_port_t, port_type;
+type imaze_port_t, port_type;
+type inetd_child_port_t, port_type;
+type innd_port_t, port_type;
+type ipp_port_t, port_type;
+type ircd_port_t, port_type;
+type isakmp_port_t, port_type;
+type jabber_client_port_t, port_type;
+type jabber_interserver_port_t, port_type;
+type kerberos_admin_port_t, port_type;
+type kerberos_master_port_t, port_type;
+type kerberos_port_t, port_type;
+type ktalkd_port_t, port_type;
+type ldap_port_t, port_type;
+type lrrd_port_t, port_type;
+type mail_port_t, port_type;
+type monopd_port_t, port_type;
+type mysqld_port_t, port_type;
+type nessus_port_t, port_type;
+type nmbd_port_t, port_type;
+type ntp_port_t, port_type;
+type openvpn_port_t, port_type;
+type pegasus_http_port_t, port_type;
+type pegasus_https_port_t, port_type;
+type pop_port_t, port_type;
+type portmap_port_t, port_type;
+type postgresql_port_t, port_type;
+type postgrey_port_t, port_type;
+type printer_port_t, port_type;
+type ptal_port_t, port_type;
+type pxe_port_t, port_type;
+type pyzor_port_t, port_type;
+type radacct_port_t, port_type;
+type radius_port_t, port_type;
+type razor_port_t, port_type;
+type rlogind_port_t, port_type;
+type rndc_port_t, port_type;
+type router_port_t, port_type;
+type rsh_port_t, port_type;
+type rsync_port_t, port_type;
+type smbd_port_t, port_type;
+type smtp_port_t, port_type;
+type snmp_port_t, port_type;
+type spamd_port_t, port_type;
+type ssh_port_t, port_type;
+type soundd_port_t, port_type;
+type socks_port_t, port_type; type stunnel_port_t, port_type;
+type swat_port_t, port_type;
+type syslogd_port_t, port_type;
+type telnetd_port_t, port_type;
+type tftp_port_t, port_type;
+type transproxy_port_t, port_type;
+type utcpserver_port_t, port_type;
+type uucpd_port_t, port_type;
+type vnc_port_t, port_type;
+type xserver_port_t, port_type;
+type xen_port_t, port_type;
+type zebra_port_t, port_type;
+type zope_port_t, port_type;
+type node_t, node_type;
+type compat_ipv4_node_t alias node_compat_ipv4_t, node_type;
+type inaddr_any_node_t alias node_inaddr_any_t, node_type;
+type node_internal_t, node_type;
+type link_local_node_t alias node_link_local_t, node_type;
+type lo_node_t alias node_lo_t, node_type;
+type mapped_ipv4_node_t alias node_mapped_ipv4_t, node_type;
+type multicast_node_t alias node_multicast_t, node_type;
+type site_local_node_t alias node_site_local_t, node_type;
+type unspec_node_t alias node_unspec_t, node_type;
+type netif_t, netif_type;
+type device_t;
+type agp_device_t;
+type apm_bios_t;
+type cardmgr_dev_t;
+type clock_device_t;
+type cpu_device_t;
+type crypt_device_t;
+type dri_device_t;
+type event_device_t;
+type framebuf_device_t;
+type lvm_control_t;
+type memory_device_t;
+type misc_device_t;
+type mouse_device_t;
+type mtrr_device_t;
+type null_device_t;
+type power_device_t;
+type printer_device_t;
+type random_device_t;
+type scanner_device_t;
+type sound_device_t;
+type sysfs_t;
+type urandom_device_t;
+type usbfs_t alias usbdevfs_t;
+type usb_device_t;
+type v4l_device_t;
+type xserver_misc_device_t;
+type zero_device_t;
+type xconsole_device_t;
+type devfs_control_t;
+type boot_t;
+type default_t, file_type, mountpoint;
+type etc_t, file_type;
+type etc_runtime_t, file_type;
+type file_t, file_type, mountpoint;
+type home_root_t, file_type, mountpoint;
+type lost_found_t, file_type;
+type mnt_t, file_type, mountpoint;
+type modules_object_t;
+type no_access_t, file_type;
+type poly_t, file_type;
+type readable_t, file_type;
+type root_t, file_type, mountpoint;
+type src_t, file_type, mountpoint;
+type system_map_t;
+type tmp_t, mountpoint; #, polydir
+type usr_t, file_type, mountpoint;
+type var_t, file_type, mountpoint;
+type var_lib_t, file_type, mountpoint;
+type var_lock_t, file_type, lockfile;
+type var_run_t, file_type, pidfile;
+type var_spool_t;
+type fs_t;
+type bdev_t;
+type binfmt_misc_fs_t;
+type capifs_t;
+type configfs_t;
+type eventpollfs_t;
+type futexfs_t;
+type hugetlbfs_t;
+type inotifyfs_t;
+type nfsd_fs_t;
+type ramfs_t;
+type romfs_t;
+type rpc_pipefs_t;
+type tmpfs_t;
+type autofs_t, noxattrfs;
+type cifs_t alias sambafs_t, noxattrfs;
+type dosfs_t, noxattrfs;
+type iso9660_t, filesystem_type, noxattrfs;
+type removable_t, noxattrfs;
+type nfs_t, filesystem_type, noxattrfs;
+type kernel_t, can_load_kernmodule;
+type debugfs_t;
+type proc_t, proc_type;
+type proc_kmsg_t, proc_type;
+type proc_kcore_t, proc_type;
+type proc_mdstat_t, proc_type;
+type proc_net_t, proc_type;
+type proc_xen_t, proc_type;
+type sysctl_t, sysctl_type;
+type sysctl_irq_t, sysctl_type;
+type sysctl_rpc_t, sysctl_type;
+type sysctl_fs_t, sysctl_type;
+type sysctl_kernel_t, sysctl_type;
+type sysctl_modprobe_t, sysctl_type;
+type sysctl_hotplug_t, sysctl_type;
+type sysctl_net_t, sysctl_type;
+type sysctl_net_unix_t, sysctl_type;
+type sysctl_vm_t, sysctl_type;
+type sysctl_dev_t, sysctl_type;
+type unlabeled_t;
+type auditd_exec_t;
+type crond_exec_t;
+type cupsd_exec_t;
+type getty_t;
+type init_t;
+type init_exec_t;
+type initrc_t;
+type initrc_exec_t;
+type login_exec_t;
+type sshd_exec_t;
+type su_exec_t;
+type udev_exec_t;
+type unconfined_t;
+type xdm_exec_t;
+type lvm_exec_t;
+type security_t;
+type bsdpty_device_t;
+type console_device_t;
+type devpts_t;
+type devtty_t;
+type ptmx_t;
+type tty_device_t, serial_device;
+type usbtty_device_t, serial_device;
+ bool secure_mode false;
+ bool secure_mode_insmod false;
+ bool secure_mode_policyload false;
+ bool allow_cvs_read_shadow false;
+ bool allow_execheap false;
+ bool allow_execmem true;
+ bool allow_execmod false;
+ bool allow_execstack true;
+ bool allow_ftpd_anon_write false;
+ bool allow_gssd_read_tmp true;
+ bool allow_httpd_anon_write false;
+ bool allow_java_execstack false;
+ bool allow_kerberos true;
+ bool allow_rsync_anon_write false;
+ bool allow_saslauthd_read_shadow false;
+ bool allow_smbd_anon_write false;
+ bool allow_ptrace false;
+ bool allow_ypbind false;
+ bool fcron_crond false;
+ bool ftp_home_dir false;
+ bool ftpd_is_daemon true;
+ bool httpd_builtin_scripting true;
+ bool httpd_can_network_connect false;
+ bool httpd_can_network_connect_db false;
+ bool httpd_can_network_relay false;
+ bool httpd_enable_cgi true;
+ bool httpd_enable_ftp_server false;
+ bool httpd_enable_homedirs true;
+ bool httpd_ssi_exec true;
+ bool httpd_tty_comm false;
+ bool httpd_unified true;
+ bool named_write_master_zones false;
+ bool nfs_export_all_rw true;
+ bool nfs_export_all_ro true;
+ bool pppd_can_insmod false;
+ bool read_default_t true;
+ bool run_ssh_inetd false;
+ bool samba_enable_home_dirs false;
+ bool spamassasin_can_network false;
+ bool squid_connect_any false;
+ bool ssh_sysadm_login false;
+ bool stunnel_is_daemon false;
+ bool use_nfs_home_dirs false;
+ bool use_samba_home_dirs false;
+ bool user_ping true;
+ bool spamd_enable_home_dirs true;
+ allow bin_t fs_t:filesystem associate;
+ allow bin_t noxattrfs:filesystem associate;
+ typeattribute bin_t file_type;
+ allow sbin_t fs_t:filesystem associate;
+ allow sbin_t noxattrfs:filesystem associate;
+ typeattribute sbin_t file_type;
+ allow ls_exec_t fs_t:filesystem associate;
+ allow ls_exec_t noxattrfs:filesystem associate;
+ typeattribute ls_exec_t file_type;
+typeattribute ls_exec_t entry_type;
+ allow shell_exec_t fs_t:filesystem associate;
+ allow shell_exec_t noxattrfs:filesystem associate;
+ typeattribute shell_exec_t file_type;
+ allow chroot_exec_t fs_t:filesystem associate;
+ allow chroot_exec_t noxattrfs:filesystem associate;
+ typeattribute chroot_exec_t file_type;
+ typeattribute ppp_device_t device_node;
+ allow ppp_device_t fs_t:filesystem associate;
+ allow ppp_device_t tmpfs_t:filesystem associate;
+ allow ppp_device_t tmp_t:filesystem associate;
+ typeattribute tun_tap_device_t device_node;
+ allow tun_tap_device_t fs_t:filesystem associate;
+ allow tun_tap_device_t tmpfs_t:filesystem associate;
+ allow tun_tap_device_t tmp_t:filesystem associate;
+typeattribute auth_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute bgp_port_t reserved_port_type;
+typeattribute comsat_port_t reserved_port_type;
+typeattribute dhcpc_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dhcpd_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute dns_port_t reserved_port_type;
+typeattribute fingerd_port_t reserved_port_type;
+typeattribute ftp_data_port_t reserved_port_type;
+typeattribute ftp_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute gopher_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute http_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute inetd_child_port_t reserved_port_type;
+typeattribute innd_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute ipp_port_t reserved_port_type;
+typeattribute isakmp_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_admin_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute kerberos_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ktalkd_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute ldap_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute nmbd_port_t reserved_port_type;
+typeattribute ntp_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute pop_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute portmap_port_t reserved_port_type;
+typeattribute printer_port_t reserved_port_type;
+typeattribute rlogind_port_t reserved_port_type;
+typeattribute rndc_port_t reserved_port_type;
+typeattribute router_port_t reserved_port_type;
+typeattribute rsh_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute rsync_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smbd_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute smtp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute snmp_port_t reserved_port_type;
+typeattribute spamd_port_t reserved_port_type;
+typeattribute ssh_port_t reserved_port_type;
+typeattribute swat_port_t reserved_port_type;
+typeattribute syslogd_port_t reserved_port_type;
+typeattribute telnetd_port_t reserved_port_type;
+typeattribute tftp_port_t reserved_port_type;
+typeattribute uucpd_port_t reserved_port_type;
+ allow device_t tmpfs_t:filesystem associate;
+ allow device_t fs_t:filesystem associate;
+ allow device_t noxattrfs:filesystem associate;
+ typeattribute device_t file_type;
+ allow device_t fs_t:filesystem associate;
+ allow device_t noxattrfs:filesystem associate;
+ typeattribute device_t file_type;
+ typeattribute device_t mountpoint;
+ allow device_t tmp_t:filesystem associate;
+ typeattribute agp_device_t device_node;
+ allow agp_device_t fs_t:filesystem associate;
+ allow agp_device_t tmpfs_t:filesystem associate;
+ allow agp_device_t tmp_t:filesystem associate;
+ typeattribute apm_bios_t device_node;
+ allow apm_bios_t fs_t:filesystem associate;
+ allow apm_bios_t tmpfs_t:filesystem associate;
+ allow apm_bios_t tmp_t:filesystem associate;
+ typeattribute cardmgr_dev_t device_node;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t tmpfs_t:filesystem associate;
+ allow cardmgr_dev_t tmp_t:filesystem associate;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t noxattrfs:filesystem associate;
+ typeattribute cardmgr_dev_t file_type;
+ allow cardmgr_dev_t fs_t:filesystem associate;
+ allow cardmgr_dev_t noxattrfs:filesystem associate;
+ typeattribute cardmgr_dev_t file_type;
+ typeattribute cardmgr_dev_t polymember;
+ allow cardmgr_dev_t tmpfs_t:filesystem associate;
+ typeattribute cardmgr_dev_t tmpfile;
+ allow cardmgr_dev_t tmp_t:filesystem associate;
+ typeattribute clock_device_t device_node;
+ allow clock_device_t fs_t:filesystem associate;
+ allow clock_device_t tmpfs_t:filesystem associate;
+ allow clock_device_t tmp_t:filesystem associate;
+ typeattribute cpu_device_t device_node;
+ allow cpu_device_t fs_t:filesystem associate;
+ allow cpu_device_t tmpfs_t:filesystem associate;
+ allow cpu_device_t tmp_t:filesystem associate;
+ typeattribute crypt_device_t device_node;
+ allow crypt_device_t fs_t:filesystem associate;
+ allow crypt_device_t tmpfs_t:filesystem associate;
+ allow crypt_device_t tmp_t:filesystem associate;
+ typeattribute dri_device_t device_node;
+ allow dri_device_t fs_t:filesystem associate;
+ allow dri_device_t tmpfs_t:filesystem associate;
+ allow dri_device_t tmp_t:filesystem associate;
+ typeattribute event_device_t device_node;
+ allow event_device_t fs_t:filesystem associate;
+ allow event_device_t tmpfs_t:filesystem associate;
+ allow event_device_t tmp_t:filesystem associate;
+ typeattribute framebuf_device_t device_node;
+ allow framebuf_device_t fs_t:filesystem associate;
+ allow framebuf_device_t tmpfs_t:filesystem associate;
+ allow framebuf_device_t tmp_t:filesystem associate;
+ typeattribute lvm_control_t device_node;
+ allow lvm_control_t fs_t:filesystem associate;
+ allow lvm_control_t tmpfs_t:filesystem associate;
+ allow lvm_control_t tmp_t:filesystem associate;
+ typeattribute memory_device_t device_node;
+ allow memory_device_t fs_t:filesystem associate;
+ allow memory_device_t tmpfs_t:filesystem associate;
+ allow memory_device_t tmp_t:filesystem associate;
+neverallow ~memory_raw_read memory_device_t:{ chr_file blk_file } read;
+neverallow ~memory_raw_write memory_device_t:{ chr_file blk_file } { append write };
+ typeattribute misc_device_t device_node;
+ allow misc_device_t fs_t:filesystem associate;
+ allow misc_device_t tmpfs_t:filesystem associate;
+ allow misc_device_t tmp_t:filesystem associate;
+ typeattribute mouse_device_t device_node;
+ allow mouse_device_t fs_t:filesystem associate;
+ allow mouse_device_t tmpfs_t:filesystem associate;
+ allow mouse_device_t tmp_t:filesystem associate;
+ typeattribute mtrr_device_t device_node;
+ allow mtrr_device_t fs_t:filesystem associate;
+ allow mtrr_device_t tmpfs_t:filesystem associate;
+ allow mtrr_device_t tmp_t:filesystem associate;
+ typeattribute null_device_t device_node;
+ allow null_device_t fs_t:filesystem associate;
+ allow null_device_t tmpfs_t:filesystem associate;
+ allow null_device_t tmp_t:filesystem associate;
+ typeattribute null_device_t mlstrustedobject;
+ typeattribute power_device_t device_node;
+ allow power_device_t fs_t:filesystem associate;
+ allow power_device_t tmpfs_t:filesystem associate;
+ allow power_device_t tmp_t:filesystem associate;
+ typeattribute printer_device_t device_node;
+ allow printer_device_t fs_t:filesystem associate;
+ allow printer_device_t tmpfs_t:filesystem associate;
+ allow printer_device_t tmp_t:filesystem associate;
+ typeattribute random_device_t device_node;
+ allow random_device_t fs_t:filesystem associate;
+ allow random_device_t tmpfs_t:filesystem associate;
+ allow random_device_t tmp_t:filesystem associate;
+ typeattribute scanner_device_t device_node;
+ allow scanner_device_t fs_t:filesystem associate;
+ allow scanner_device_t tmpfs_t:filesystem associate;
+ allow scanner_device_t tmp_t:filesystem associate;
+ typeattribute sound_device_t device_node;
+ allow sound_device_t fs_t:filesystem associate;
+ allow sound_device_t tmpfs_t:filesystem associate;
+ allow sound_device_t tmp_t:filesystem associate;
+ allow sysfs_t fs_t:filesystem associate;
+ allow sysfs_t noxattrfs:filesystem associate;
+ typeattribute sysfs_t file_type;
+ typeattribute sysfs_t mountpoint;
+ typeattribute sysfs_t filesystem_type;
+ allow sysfs_t self:filesystem associate;
+ typeattribute urandom_device_t device_node;
+ allow urandom_device_t fs_t:filesystem associate;
+ allow urandom_device_t tmpfs_t:filesystem associate;
+ allow urandom_device_t tmp_t:filesystem associate;
+ allow usbfs_t fs_t:filesystem associate;
+ allow usbfs_t noxattrfs:filesystem associate;
+ typeattribute usbfs_t file_type;
+ typeattribute usbfs_t mountpoint;
+ typeattribute usbfs_t filesystem_type;
+ allow usbfs_t self:filesystem associate;
+ typeattribute usbfs_t noxattrfs;
+ typeattribute usb_device_t device_node;
+ allow usb_device_t fs_t:filesystem associate;
+ allow usb_device_t tmpfs_t:filesystem associate;
+ allow usb_device_t tmp_t:filesystem associate;
+ typeattribute v4l_device_t device_node;
+ allow v4l_device_t fs_t:filesystem associate;
+ allow v4l_device_t tmpfs_t:filesystem associate;
+ allow v4l_device_t tmp_t:filesystem associate;
+ typeattribute xserver_misc_device_t device_node;
+ allow xserver_misc_device_t fs_t:filesystem associate;
+ allow xserver_misc_device_t tmpfs_t:filesystem associate;
+ allow xserver_misc_device_t tmp_t:filesystem associate;
+ typeattribute zero_device_t device_node;
+ allow zero_device_t fs_t:filesystem associate;
+ allow zero_device_t tmpfs_t:filesystem associate;
+ allow zero_device_t tmp_t:filesystem associate;
+ typeattribute zero_device_t mlstrustedobject;
+ allow xconsole_device_t fs_t:filesystem associate;
+ allow xconsole_device_t noxattrfs:filesystem associate;
+ typeattribute xconsole_device_t file_type;
+ allow xconsole_device_t tmpfs_t:filesystem associate;
+ allow xconsole_device_t tmp_t:filesystem associate;
+ typeattribute devfs_control_t device_node;
+ allow devfs_control_t fs_t:filesystem associate;
+ allow devfs_control_t tmpfs_t:filesystem associate;
+ allow devfs_control_t tmp_t:filesystem associate;
+neverallow domain ~domain:process { transition dyntransition };
+neverallow { domain -set_curr_context } self:process setcurrent;
+neverallow { domain unlabeled_t } ~{ domain unlabeled_t }:process *;
+neverallow ~{ domain unlabeled_t } *:process *;
+allow file_type self:filesystem associate;
+ allow boot_t fs_t:filesystem associate;
+ allow boot_t noxattrfs:filesystem associate;
+ typeattribute boot_t file_type;
+ allow boot_t fs_t:filesystem associate;
+ allow boot_t noxattrfs:filesystem associate;
+ typeattribute boot_t file_type;
+ typeattribute boot_t mountpoint;
+ allow default_t fs_t:filesystem associate;
+ allow default_t noxattrfs:filesystem associate;
+ allow etc_t fs_t:filesystem associate;
+ allow etc_t noxattrfs:filesystem associate;
+ allow etc_runtime_t fs_t:filesystem associate;
+ allow etc_runtime_t noxattrfs:filesystem associate;
+ allow file_t fs_t:filesystem associate;
+ allow file_t noxattrfs:filesystem associate;
+ allow kernel_t file_t:dir mounton;
+ allow home_root_t fs_t:filesystem associate;
+ allow home_root_t noxattrfs:filesystem associate;
+ allow home_root_t fs_t:filesystem associate;
+ allow home_root_t noxattrfs:filesystem associate;
+ typeattribute home_root_t file_type;
+ typeattribute home_root_t polyparent;
+ allow lost_found_t fs_t:filesystem associate;
+ allow lost_found_t noxattrfs:filesystem associate;
+ allow mnt_t fs_t:filesystem associate;
+ allow mnt_t noxattrfs:filesystem associate;
+ allow modules_object_t fs_t:filesystem associate;
+ allow modules_object_t noxattrfs:filesystem associate;
+ typeattribute modules_object_t file_type;
+ allow no_access_t fs_t:filesystem associate;
+ allow no_access_t noxattrfs:filesystem associate;
+ allow poly_t fs_t:filesystem associate;
+ allow poly_t noxattrfs:filesystem associate;
+ allow readable_t fs_t:filesystem associate;
+ allow readable_t noxattrfs:filesystem associate;
+ allow root_t fs_t:filesystem associate;
+ allow root_t noxattrfs:filesystem associate;
+ allow root_t fs_t:filesystem associate;
+ allow root_t noxattrfs:filesystem associate;
+ typeattribute root_t file_type;
+ typeattribute root_t polyparent;
+ allow kernel_t root_t:dir mounton;
+ allow src_t fs_t:filesystem associate;
+ allow src_t noxattrfs:filesystem associate;
+ allow system_map_t fs_t:filesystem associate;
+ allow system_map_t noxattrfs:filesystem associate;
+ typeattribute system_map_t file_type;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ typeattribute tmp_t polymember;
+ allow tmp_t tmpfs_t:filesystem associate;
+ typeattribute tmp_t tmpfile;
+ allow tmp_t tmp_t:filesystem associate;
+ allow tmp_t fs_t:filesystem associate;
+ allow tmp_t noxattrfs:filesystem associate;
+ typeattribute tmp_t file_type;
+ typeattribute tmp_t polyparent;
+ allow usr_t fs_t:filesystem associate;
+ allow usr_t noxattrfs:filesystem associate;
+ allow var_t fs_t:filesystem associate;
+ allow var_t noxattrfs:filesystem associate;
+ allow var_lib_t fs_t:filesystem associate;
+ allow var_lib_t noxattrfs:filesystem associate;
+ allow var_lock_t fs_t:filesystem associate;
+ allow var_lock_t noxattrfs:filesystem associate;
+ allow var_run_t fs_t:filesystem associate;
+ allow var_run_t noxattrfs:filesystem associate;
+ allow var_spool_t fs_t:filesystem associate;
+ allow var_spool_t noxattrfs:filesystem associate;
+ typeattribute var_spool_t file_type;
+ allow var_spool_t fs_t:filesystem associate;
+ allow var_spool_t noxattrfs:filesystem associate;
+ typeattribute var_spool_t file_type;
+ typeattribute var_spool_t polymember;
+ allow var_spool_t tmpfs_t:filesystem associate;
+ typeattribute var_spool_t tmpfile;
+ allow var_spool_t tmp_t:filesystem associate;
+ typeattribute fs_t filesystem_type;
+ allow fs_t self:filesystem associate;
+ typeattribute bdev_t filesystem_type;
+ allow bdev_t self:filesystem associate;
+ typeattribute binfmt_misc_fs_t filesystem_type;
+ allow binfmt_misc_fs_t self:filesystem associate;
+ allow binfmt_misc_fs_t fs_t:filesystem associate;
+ allow binfmt_misc_fs_t noxattrfs:filesystem associate;
+ typeattribute binfmt_misc_fs_t file_type;
+ typeattribute binfmt_misc_fs_t mountpoint;
+ typeattribute capifs_t filesystem_type;
+ allow capifs_t self:filesystem associate;
+ typeattribute configfs_t filesystem_type;
+ allow configfs_t self:filesystem associate;
+ typeattribute eventpollfs_t filesystem_type;
+ allow eventpollfs_t self:filesystem associate;
+ typeattribute futexfs_t filesystem_type;
+ allow futexfs_t self:filesystem associate;
+ typeattribute hugetlbfs_t filesystem_type;
+ allow hugetlbfs_t self:filesystem associate;
+ allow hugetlbfs_t fs_t:filesystem associate;
+ allow hugetlbfs_t noxattrfs:filesystem associate;
+ typeattribute hugetlbfs_t file_type;
+ typeattribute hugetlbfs_t mountpoint;
+ typeattribute inotifyfs_t filesystem_type;
+ allow inotifyfs_t self:filesystem associate;
+ typeattribute nfsd_fs_t filesystem_type;
+ allow nfsd_fs_t self:filesystem associate;
+ typeattribute ramfs_t filesystem_type;
+ allow ramfs_t self:filesystem associate;
+ typeattribute romfs_t filesystem_type;
+ allow romfs_t self:filesystem associate;
+ typeattribute rpc_pipefs_t filesystem_type;
+ allow rpc_pipefs_t self:filesystem associate;
+ typeattribute tmpfs_t filesystem_type;
+ allow tmpfs_t self:filesystem associate;
+ allow tmpfs_t fs_t:filesystem associate;
+ allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute tmpfs_t file_type;
+ allow tmpfs_t fs_t:filesystem associate;
+ allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute tmpfs_t file_type;
+ typeattribute tmpfs_t mountpoint;
+allow tmpfs_t noxattrfs:filesystem associate;
+ typeattribute autofs_t filesystem_type;
+ allow autofs_t self:filesystem associate;
+ allow autofs_t fs_t:filesystem associate;
+ allow autofs_t noxattrfs:filesystem associate;
+ typeattribute autofs_t file_type;
+ typeattribute autofs_t mountpoint;
+ typeattribute cifs_t filesystem_type;
+ allow cifs_t self:filesystem associate;
+ typeattribute dosfs_t filesystem_type;
+ allow dosfs_t self:filesystem associate;
+allow dosfs_t fs_t:filesystem associate;
+ typeattribute iso9660_t filesystem_type;
+ allow iso9660_t self:filesystem associate;
+allow removable_t noxattrfs:filesystem associate;
+ typeattribute removable_t filesystem_type;
+ allow removable_t self:filesystem associate;
+ allow removable_t fs_t:filesystem associate;
+ allow removable_t noxattrfs:filesystem associate;
+ typeattribute removable_t file_type;
+ typeattribute removable_t usercanread;
+ typeattribute nfs_t filesystem_type;
+ allow nfs_t self:filesystem associate;
+ allow nfs_t fs_t:filesystem associate;
+ allow nfs_t noxattrfs:filesystem associate;
+ typeattribute nfs_t file_type;
+ typeattribute nfs_t mountpoint;
+neverallow ~can_load_kernmodule self:capability sys_module;
+role system_r;
+role sysadm_r;
+role staff_r;
+role user_r;
+role secadm_r;
+ typeattribute kernel_t domain;
+ allow kernel_t self:dir { read getattr lock search ioctl };
+ allow kernel_t self:lnk_file { read getattr lock ioctl };
+ allow kernel_t self:file { getattr read write append ioctl lock };
+ allow kernel_t self:process { fork sigchld };
+ role secadm_r types kernel_t;
+ role sysadm_r types kernel_t;
+ role user_r types kernel_t;
+ role staff_r types kernel_t;
+ typeattribute kernel_t privrangetrans;
+role system_r types kernel_t;
+ typeattribute debugfs_t filesystem_type;
+ allow debugfs_t self:filesystem associate;
+allow debugfs_t self:filesystem associate;
+ allow proc_t fs_t:filesystem associate;
+ allow proc_t noxattrfs:filesystem associate;
+ typeattribute proc_t file_type;
+ typeattribute proc_t mountpoint;
+ typeattribute proc_t filesystem_type;
+ allow proc_t self:filesystem associate;
+neverallow ~can_receive_kernel_messages proc_kmsg_t:file ~getattr;
+neverallow { domain -kern_unconfined } proc_kcore_t:file ~getattr;
+ allow sysctl_t fs_t:filesystem associate;
+ allow sysctl_t noxattrfs:filesystem associate;
+ typeattribute sysctl_t file_type;
+ typeattribute sysctl_t mountpoint;
+ allow sysctl_fs_t fs_t:filesystem associate;
+ allow sysctl_fs_t noxattrfs:filesystem associate;
+ typeattribute sysctl_fs_t file_type;
+ typeattribute sysctl_fs_t mountpoint;
+allow kernel_t self:capability *;
+allow kernel_t unlabeled_t:dir mounton;
+allow kernel_t self:process ~{ ptrace setcurrent setexec setfscreate setrlimit execmem execstack execheap };
+allow kernel_t self:shm { associate getattr setattr create destroy read write lock unix_read unix_write };
+allow kernel_t self:sem { associate getattr setattr create destroy read write unix_read unix_write };
+allow kernel_t self:msg { send receive };
+allow kernel_t self:msgq { associate getattr setattr create destroy read write enqueue unix_read unix_write };
+allow kernel_t self:unix_dgram_socket { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } };
+allow kernel_t self:unix_stream_socket { { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } } listen accept };
+allow kernel_t self:unix_dgram_socket sendto;
+allow kernel_t self:unix_stream_socket connectto;
+allow kernel_t self:fifo_file { getattr read write append ioctl lock };
+allow kernel_t self:sock_file { read getattr lock ioctl };
+allow kernel_t self:fd use;
+allow kernel_t proc_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_t:{ lnk_file file } { read getattr lock ioctl };
+allow kernel_t proc_net_t:dir { read getattr lock search ioctl };
+allow kernel_t proc_net_t:file { read getattr lock ioctl };
+allow kernel_t proc_mdstat_t:file { read getattr lock ioctl };
+allow kernel_t proc_kcore_t:file getattr;
+allow kernel_t proc_kmsg_t:file getattr;
+allow kernel_t sysctl_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:dir { read getattr lock search ioctl };
+allow kernel_t sysctl_kernel_t:file { read getattr lock ioctl };
+allow kernel_t unlabeled_t:fifo_file { getattr read write append ioctl lock };
+ allow kernel_t unlabeled_t:association { sendto recvfrom };
+ allow kernel_t netif_type:netif rawip_send;
+ allow kernel_t netif_type:netif rawip_recv;
+ allow kernel_t node_type:node rawip_send;
+ allow kernel_t node_type:node rawip_recv;
+ allow kernel_t netif_t:netif rawip_send;
+ allow kernel_t netif_type:netif { tcp_send tcp_recv };
+ allow kernel_t node_type:node { tcp_send tcp_recv };
+ allow kernel_t node_t:node rawip_send;
+ allow kernel_t multicast_node_t:node rawip_send;
+ allow kernel_t sysfs_t:dir { read getattr lock search ioctl };
+ allow kernel_t sysfs_t:{ file lnk_file } { read getattr lock ioctl };
+ allow kernel_t usbfs_t:dir search;
+ allow kernel_t filesystem_type:filesystem mount;
+ allow kernel_t security_t:dir { read search getattr };
+ allow kernel_t security_t:file { getattr read write };
+ typeattribute kernel_t can_load_policy;
+ if(!secure_mode_policyload) {
+ allow kernel_t security_t:security load_policy;
+ auditallow kernel_t security_t:security load_policy;
+ }
+ allow kernel_t device_t:dir { read getattr lock search ioctl };
+ allow kernel_t device_t:lnk_file { getattr read };
+ allow kernel_t console_device_t:chr_file { getattr read write append ioctl lock };
+ allow kernel_t bin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t shell_exec_t:file { { read getattr lock execute ioctl } execute_no_trans };
+ allow kernel_t sbin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:dir { read getattr lock search ioctl };
+ allow kernel_t bin_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t bin_t:file { { read getattr lock execute ioctl } execute_no_trans };
+ allow kernel_t domain:process signal;
+ allow kernel_t proc_t:dir search;
+ allow kernel_t domain:dir search;
+ allow kernel_t root_t:dir { read getattr lock search ioctl };
+ allow kernel_t root_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t etc_t:dir { read getattr lock search ioctl };
+ allow kernel_t home_root_t:dir { read getattr lock search ioctl };
+ allow kernel_t usr_t:dir { read getattr lock search ioctl };
+ allow kernel_t usr_t:{ file lnk_file } { read getattr lock ioctl };
+ typeattribute kernel_t mlsprocread;
+ typeattribute kernel_t mlsprocwrite;
+ allow kernel_t self:capability *;
+ allow kernel_t self:fifo_file { create ioctl read getattr lock write setattr append link unlink rename };
+ allow kernel_t self:process transition;
+ allow kernel_t self:file { getattr read write append ioctl lock };
+ allow kernel_t self:nscd *;
+ allow kernel_t self:dbus *;
+ allow kernel_t self:passwd *;
+ allow kernel_t proc_type:{ dir file } *;
+ allow kernel_t sysctl_t:{ dir file } *;
+ allow kernel_t kernel_t:system *;
+ allow kernel_t unlabeled_t:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+ allow kernel_t unlabeled_t:filesystem *;
+ allow kernel_t unlabeled_t:association *;
+ typeattribute kernel_t can_load_kernmodule, can_receive_kernel_messages;
+ typeattribute kernel_t kern_unconfined;
+ allow kernel_t { proc_t proc_net_t }:dir search;
+ allow kernel_t sysctl_type:dir { read getattr lock search ioctl };
+ allow kernel_t sysctl_type:file { { getattr read write append ioctl lock } setattr };
+ allow kernel_t node_type:node *;
+ allow kernel_t netif_type:netif *;
+ allow kernel_t port_type:tcp_socket { send_msg recv_msg name_connect };
+ allow kernel_t port_type:udp_socket { send_msg recv_msg };
+ allow kernel_t port_type:{ tcp_socket udp_socket rawip_socket } name_bind;
+ allow kernel_t node_type:{ tcp_socket udp_socket rawip_socket } node_bind;
+ allow kernel_t unlabeled_t:association { sendto recvfrom };
+ allow kernel_t device_node:{ chr_file blk_file } *;
+ allow kernel_t mtrr_device_t:{ dir file } *;
+ allow kernel_t self:capability sys_rawio;
+ typeattribute kernel_t memory_raw_write, memory_raw_read;
+ typeattribute kernel_t unconfined_domain_type;
+ typeattribute kernel_t can_change_process_identity;
+ typeattribute kernel_t can_change_process_role;
+ typeattribute kernel_t can_change_object_identity;
+ typeattribute kernel_t set_curr_context;
+ allow kernel_t domain:{ { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } socket key_socket } *;
+ allow kernel_t domain:fd use;
+ allow kernel_t domain:fifo_file { getattr read write append ioctl lock };
+ allow kernel_t domain:process ~{ transition dyntransition execmem execstack execheap };
+ allow kernel_t domain:{ sem msgq shm } *;
+ allow kernel_t domain:msg { send receive };
+ allow kernel_t domain:dir { read getattr lock search ioctl };
+ allow kernel_t domain:file { read getattr lock ioctl };
+ allow kernel_t domain:lnk_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:dir { read getattr lock search ioctl };
+ dontaudit kernel_t domain:lnk_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:file { read getattr lock ioctl };
+ dontaudit kernel_t domain:sock_file { read getattr lock ioctl };
+ dontaudit kernel_t domain:fifo_file { read getattr lock ioctl };
+ allow kernel_t file_type:{ file chr_file } ~execmod;
+ allow kernel_t file_type:{ dir lnk_file sock_file fifo_file blk_file } *;
+ allow kernel_t file_type:filesystem *;
+ allow kernel_t file_type:{ unix_stream_socket unix_dgram_socket } name_bind;
+ if (allow_execmod) {
+ allow kernel_t file_type:file execmod;
+ }
+ allow kernel_t filesystem_type:filesystem *;
+ allow kernel_t filesystem_type:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *;
+ allow kernel_t security_t:dir { getattr search read };
+ allow kernel_t security_t:file { getattr read write };
+ typeattribute kernel_t can_load_policy, can_setenforce, can_setsecparam;
+ if(!secure_mode_policyload) {
+ allow kernel_t security_t:security *;
+ auditallow kernel_t security_t:security { load_policy setenforce setbool };
+ }
+ if (allow_execheap) {
+ allow kernel_t self:process execheap;
+ }
+ if (allow_execmem) {
+ allow kernel_t self:process execmem;
+ }
+ if (allow_execmem && allow_execstack) {
+ allow kernel_t self:process execstack;
+ auditallow kernel_t self:process execstack;
+ } else {
+ }
+ if (allow_execheap) {
+ auditallow kernel_t self:process execheap;
+ }
+ if (allow_execmem) {
+ auditallow kernel_t self:process execmem;
+ }
+ if (read_default_t) {
+ allow kernel_t default_t:dir { read getattr lock search ioctl };
+ allow kernel_t default_t:file { read getattr lock ioctl };
+ allow kernel_t default_t:lnk_file { read getattr lock ioctl };
+ allow kernel_t default_t:sock_file { read getattr lock ioctl };
+ allow kernel_t default_t:fifo_file { read getattr lock ioctl };
+ }
+ allow unlabeled_t self:filesystem associate;
+range_transition getty_t login_exec_t s0 - s0:c0.c255;
+range_transition init_t xdm_exec_t s0 - s0:c0.c255;
+range_transition initrc_t crond_exec_t s0 - s0:c0.c255;
+range_transition initrc_t cupsd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t sshd_exec_t s0 - s0:c0.c255;
+range_transition initrc_t udev_exec_t s0 - s0:c0.c255;
+range_transition initrc_t xdm_exec_t s0 - s0:c0.c255;
+range_transition kernel_t udev_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t su_exec_t s0 - s0:c0.c255;
+range_transition unconfined_t initrc_exec_t s0;
+ typeattribute security_t filesystem_type;
+ allow security_t self:filesystem associate;
+ typeattribute security_t mlstrustedobject;
+neverallow ~can_load_policy security_t:security load_policy;
+neverallow ~can_setenforce security_t:security setenforce;
+neverallow ~can_setsecparam security_t:security setsecparam;
+ typeattribute bsdpty_device_t device_node;
+ allow bsdpty_device_t fs_t:filesystem associate;
+ allow bsdpty_device_t tmpfs_t:filesystem associate;
+ allow bsdpty_device_t tmp_t:filesystem associate;
+ typeattribute console_device_t device_node;
+ allow console_device_t fs_t:filesystem associate;
+ allow console_device_t tmpfs_t:filesystem associate;
+ allow console_device_t tmp_t:filesystem associate;
+ allow devpts_t fs_t:filesystem associate;
+ allow devpts_t noxattrfs:filesystem associate;
+ typeattribute devpts_t file_type;
+ typeattribute devpts_t mountpoint;
+ allow devpts_t tmpfs_t:filesystem associate;
+ allow devpts_t tmp_t:filesystem associate;
+ typeattribute devpts_t filesystem_type;
+ allow devpts_t self:filesystem associate;
+ typeattribute devpts_t ttynode, ptynode;
+ typeattribute devtty_t device_node;
+ allow devtty_t fs_t:filesystem associate;
+ allow devtty_t tmpfs_t:filesystem associate;
+ allow devtty_t tmp_t:filesystem associate;
+ typeattribute devtty_t mlstrustedobject;
+ typeattribute ptmx_t device_node;
+ allow ptmx_t fs_t:filesystem associate;
+ allow ptmx_t tmpfs_t:filesystem associate;
+ allow ptmx_t tmp_t:filesystem associate;
+ typeattribute ptmx_t mlstrustedobject;
+ typeattribute tty_device_t device_node;
+ allow tty_device_t fs_t:filesystem associate;
+ allow tty_device_t tmpfs_t:filesystem associate;
+ allow tty_device_t tmp_t:filesystem associate;
+ typeattribute tty_device_t ttynode;
+ typeattribute usbtty_device_t device_node;
+ allow usbtty_device_t fs_t:filesystem associate;
+ allow usbtty_device_t tmpfs_t:filesystem associate;
+ allow usbtty_device_t tmp_t:filesystem associate;
+user system_u roles { system_r } level s0 range s0 - s0:c0.c255;
+user user_u roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+ user root roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255;
+constrain process transition
+ ( u1 == u2
+ or t1 == can_change_process_identity
+);
+constrain process transition
+ ( r1 == r2
+ or t1 == can_change_process_role
+);
+constrain process dyntransition
+ ( u1 == u2 and r1 == r2 );
+constrain { dir file lnk_file sock_file fifo_file chr_file blk_file } { create relabelto relabelfrom }
+ ( u1 == u2 or t1 == can_change_object_identity );
+constrain { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } { create relabelto relabelfrom }
+ ( u1 == u2 or t1 == can_change_object_identity );
+sid port system_u:object_r:port_t:s0
+sid node system_u:object_r:node_t:s0
+sid netif system_u:object_r:netif_t:s0
+sid devnull system_u:object_r:null_device_t:s0
+sid file system_u:object_r:file_t:s0
+sid fs system_u:object_r:fs_t:s0
+sid kernel system_u:system_r:kernel_t:s0
+sid sysctl system_u:object_r:sysctl_t:s0
+sid unlabeled system_u:object_r:unlabeled_t:s0
+sid any_socket system_u:object_r:unlabeled_t:s0
+sid file_labels system_u:object_r:unlabeled_t:s0
+sid icmp_socket system_u:object_r:unlabeled_t:s0
+sid igmp_packet system_u:object_r:unlabeled_t:s0
+sid init system_u:object_r:unlabeled_t:s0
+sid kmod system_u:object_r:unlabeled_t:s0
+sid netmsg system_u:object_r:unlabeled_t:s0
+sid policy system_u:object_r:unlabeled_t:s0
+sid scmp_packet system_u:object_r:unlabeled_t:s0
+sid sysctl_modprobe system_u:object_r:unlabeled_t:s0
+sid sysctl_fs system_u:object_r:unlabeled_t:s0
+sid sysctl_kernel system_u:object_r:unlabeled_t:s0
+sid sysctl_net system_u:object_r:unlabeled_t:s0
+sid sysctl_net_unix system_u:object_r:unlabeled_t:s0
+sid sysctl_vm system_u:object_r:unlabeled_t:s0
+sid sysctl_dev system_u:object_r:unlabeled_t:s0
+sid tcp_socket system_u:object_r:unlabeled_t:s0
+sid security system_u:object_r:security_t:s0
+fs_use_xattr ext2 system_u:object_r:fs_t:s0;
+fs_use_xattr ext3 system_u:object_r:fs_t:s0;
+fs_use_xattr gfs system_u:object_r:fs_t:s0;
+fs_use_xattr jfs system_u:object_r:fs_t:s0;
+fs_use_xattr reiserfs system_u:object_r:fs_t:s0;
+fs_use_xattr xfs system_u:object_r:fs_t:s0;
+fs_use_task pipefs system_u:object_r:fs_t:s0;
+fs_use_task sockfs system_u:object_r:fs_t:s0;
+fs_use_trans mqueue system_u:object_r:tmpfs_t:s0;
+fs_use_trans shm system_u:object_r:tmpfs_t:s0;
+fs_use_trans tmpfs system_u:object_r:tmpfs_t:s0;
+fs_use_trans devpts system_u:object_r:devpts_t:s0;
+genfscon proc /mtrr system_u:object_r:mtrr_device_t:s0
+genfscon sysfs / system_u:object_r:sysfs_t:s0
+genfscon usbfs / system_u:object_r:usbfs_t:s0
+genfscon usbdevfs / system_u:object_r:usbfs_t:s0
+genfscon rootfs / system_u:object_r:root_t:s0
+genfscon bdev / system_u:object_r:bdev_t:s0
+genfscon binfmt_misc / system_u:object_r:binfmt_misc_fs_t:s0
+genfscon capifs / system_u:object_r:capifs_t:s0
+genfscon configfs / system_u:object_r:configfs_t:s0
+genfscon eventpollfs / system_u:object_r:eventpollfs_t:s0
+genfscon futexfs / system_u:object_r:futexfs_t:s0
+genfscon hugetlbfs / system_u:object_r:hugetlbfs_t:s0
+genfscon inotifyfs / system_u:object_r:inotifyfs_t:s0
+genfscon nfsd / system_u:object_r:nfsd_fs_t:s0
+genfscon ramfs / system_u:object_r:ramfs_t:s0
+genfscon romfs / system_u:object_r:romfs_t:s0
+genfscon cramfs / system_u:object_r:romfs_t:s0
+genfscon rpc_pipefs / system_u:object_r:rpc_pipefs_t:s0
+genfscon autofs / system_u:object_r:autofs_t:s0
+genfscon automount / system_u:object_r:autofs_t:s0
+genfscon cifs / system_u:object_r:cifs_t:s0
+genfscon smbfs / system_u:object_r:cifs_t:s0
+genfscon fat / system_u:object_r:dosfs_t:s0
+genfscon msdos / system_u:object_r:dosfs_t:s0
+genfscon ntfs / system_u:object_r:dosfs_t:s0
+genfscon vfat / system_u:object_r:dosfs_t:s0
+genfscon iso9660 / system_u:object_r:iso9660_t:s0
+genfscon udf / system_u:object_r:iso9660_t:s0
+genfscon nfs / system_u:object_r:nfs_t:s0
+genfscon nfs4 / system_u:object_r:nfs_t:s0
+genfscon afs / system_u:object_r:nfs_t:s0
+genfscon hfsplus / system_u:object_r:nfs_t:s0
+genfscon debugfs / system_u:object_r:debugfs_t:s0
+genfscon proc / system_u:object_r:proc_t:s0
+genfscon proc /sysvipc system_u:object_r:proc_t:s0
+genfscon proc /kmsg system_u:object_r:proc_kmsg_t:s0
+genfscon proc /kcore system_u:object_r:proc_kcore_t:s0
+genfscon proc /mdstat system_u:object_r:proc_mdstat_t:s0
+genfscon proc /net system_u:object_r:proc_net_t:s0
+genfscon proc /xen system_u:object_r:proc_xen_t:s0
+genfscon proc /sys system_u:object_r:sysctl_t:s0
+genfscon proc /irq system_u:object_r:sysctl_irq_t:s0
+genfscon proc /net/rpc system_u:object_r:sysctl_rpc_t:s0
+genfscon proc /sys/fs system_u:object_r:sysctl_fs_t:s0
+genfscon proc /sys/kernel system_u:object_r:sysctl_kernel_t:s0
+genfscon proc /sys/kernel/modprobe system_u:object_r:sysctl_modprobe_t:s0
+genfscon proc /sys/kernel/hotplug system_u:object_r:sysctl_hotplug_t:s0
+genfscon proc /sys/net system_u:object_r:sysctl_net_t:s0
+genfscon proc /sys/net/unix system_u:object_r:sysctl_net_unix_t:s0
+genfscon proc /sys/vm system_u:object_r:sysctl_vm_t:s0
+genfscon proc /sys/dev system_u:object_r:sysctl_dev_t:s0
+genfscon selinuxfs / system_u:object_r:security_t:s0
+portcon udp 7007 system_u:object_r:afs_bos_port_t:s0
+portcon tcp 2040 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7000 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7005 system_u:object_r:afs_fs_port_t:s0
+portcon udp 7004 system_u:object_r:afs_ka_port_t:s0
+portcon udp 7002 system_u:object_r:afs_pt_port_t:s0
+portcon udp 7003 system_u:object_r:afs_vl_port_t:s0
+portcon udp 10080 system_u:object_r:amanda_port_t:s0
+portcon tcp 10080 system_u:object_r:amanda_port_t:s0
+portcon udp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10081 system_u:object_r:amanda_port_t:s0
+portcon tcp 10082 system_u:object_r:amanda_port_t:s0
+portcon tcp 10083 system_u:object_r:amanda_port_t:s0
+portcon tcp 10024 system_u:object_r:amavisd_recv_port_t:s0
+portcon tcp 10025 system_u:object_r:amavisd_send_port_t:s0
+portcon tcp 1720 system_u:object_r:asterisk_port_t:s0
+portcon udp 2427 system_u:object_r:asterisk_port_t:s0
+portcon udp 2727 system_u:object_r:asterisk_port_t:s0
+portcon udp 4569 system_u:object_r:asterisk_port_t:s0
+portcon udp 5060 system_u:object_r:asterisk_port_t:s0
+portcon tcp 113 system_u:object_r:auth_port_t:s0
+portcon tcp 179 system_u:object_r:bgp_port_t:s0
+portcon udp 179 system_u:object_r:bgp_port_t:s0
+portcon tcp 3310 system_u:object_r:clamd_port_t:s0
+portcon udp 4041 system_u:object_r:clockspeed_port_t:s0
+portcon udp 512 system_u:object_r:comsat_port_t:s0
+portcon tcp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 2401 system_u:object_r:cvs_port_t:s0
+portcon udp 6276 system_u:object_r:dcc_port_t:s0
+portcon udp 6277 system_u:object_r:dcc_port_t:s0
+portcon tcp 1178 system_u:object_r:dbskkd_port_t:s0
+portcon udp 68 system_u:object_r:dhcpc_port_t:s0
+portcon udp 67 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 647 system_u:object_r:dhcpd_port_t:s0
+portcon udp 647 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 847 system_u:object_r:dhcpd_port_t:s0
+portcon udp 847 system_u:object_r:dhcpd_port_t:s0
+portcon tcp 2628 system_u:object_r:dict_port_t:s0
+portcon tcp 3632 system_u:object_r:distccd_port_t:s0
+portcon udp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 53 system_u:object_r:dns_port_t:s0
+portcon tcp 79 system_u:object_r:fingerd_port_t:s0
+portcon tcp 20 system_u:object_r:ftp_data_port_t:s0
+portcon tcp 21 system_u:object_r:ftp_port_t:s0
+portcon udp 1718 system_u:object_r:gatekeeper_port_t:s0
+portcon udp 1719 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1721 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 7000 system_u:object_r:gatekeeper_port_t:s0
+portcon tcp 1213 system_u:object_r:giftd_port_t:s0
+portcon tcp 70 system_u:object_r:gopher_port_t:s0
+portcon udp 70 system_u:object_r:gopher_port_t:s0
+portcon tcp 3128 system_u:object_r:http_cache_port_t:s0
+portcon udp 3130 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8080 system_u:object_r:http_cache_port_t:s0
+portcon tcp 8118 system_u:object_r:http_cache_port_t:s0
+portcon tcp 80 system_u:object_r:http_port_t:s0
+portcon tcp 443 system_u:object_r:http_port_t:s0
+portcon tcp 488 system_u:object_r:http_port_t:s0
+portcon tcp 8008 system_u:object_r:http_port_t:s0
+portcon tcp 9050 system_u:object_r:http_port_t:s0
+portcon tcp 5335 system_u:object_r:howl_port_t:s0
+portcon udp 5353 system_u:object_r:howl_port_t:s0
+portcon tcp 50000 system_u:object_r:hplip_port_t:s0
+portcon tcp 50002 system_u:object_r:hplip_port_t:s0
+portcon tcp 9010 system_u:object_r:i18n_input_port_t:s0
+portcon tcp 5323 system_u:object_r:imaze_port_t:s0
+portcon udp 5323 system_u:object_r:imaze_port_t:s0
+portcon tcp 7 system_u:object_r:inetd_child_port_t:s0
+portcon udp 7 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 9 system_u:object_r:inetd_child_port_t:s0
+portcon udp 9 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 13 system_u:object_r:inetd_child_port_t:s0
+portcon udp 13 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 19 system_u:object_r:inetd_child_port_t:s0
+portcon udp 19 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 37 system_u:object_r:inetd_child_port_t:s0
+portcon udp 37 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 512 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 543 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 544 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 891 system_u:object_r:inetd_child_port_t:s0
+portcon udp 891 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 892 system_u:object_r:inetd_child_port_t:s0
+portcon udp 892 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 2105 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 5666 system_u:object_r:inetd_child_port_t:s0
+portcon tcp 119 system_u:object_r:innd_port_t:s0
+portcon tcp 631 system_u:object_r:ipp_port_t:s0
+portcon udp 631 system_u:object_r:ipp_port_t:s0
+portcon tcp 6667 system_u:object_r:ircd_port_t:s0
+portcon udp 500 system_u:object_r:isakmp_port_t:s0
+portcon tcp 5222 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5223 system_u:object_r:jabber_client_port_t:s0
+portcon tcp 5269 system_u:object_r:jabber_interserver_port_t:s0
+portcon tcp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon udp 464 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 749 system_u:object_r:kerberos_admin_port_t:s0
+portcon tcp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon udp 4444 system_u:object_r:kerberos_master_port_t:s0
+portcon tcp 88 system_u:object_r:kerberos_port_t:s0
+portcon udp 88 system_u:object_r:kerberos_port_t:s0
+portcon tcp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 750 system_u:object_r:kerberos_port_t:s0
+portcon udp 517 system_u:object_r:ktalkd_port_t:s0
+portcon udp 518 system_u:object_r:ktalkd_port_t:s0
+portcon tcp 389 system_u:object_r:ldap_port_t:s0
+portcon udp 389 system_u:object_r:ldap_port_t:s0
+portcon tcp 636 system_u:object_r:ldap_port_t:s0
+portcon udp 636 system_u:object_r:ldap_port_t:s0
+portcon tcp 2000 system_u:object_r:mail_port_t:s0
+portcon tcp 1234 system_u:object_r:monopd_port_t:s0
+portcon tcp 3306 system_u:object_r:mysqld_port_t:s0
+portcon tcp 1241 system_u:object_r:nessus_port_t:s0
+portcon udp 137 system_u:object_r:nmbd_port_t:s0
+portcon udp 138 system_u:object_r:nmbd_port_t:s0
+portcon udp 139 system_u:object_r:nmbd_port_t:s0
+portcon udp 123 system_u:object_r:ntp_port_t:s0
+portcon udp 5000 system_u:object_r:openvpn_port_t:s0
+portcon tcp 5988 system_u:object_r:pegasus_http_port_t:s0
+portcon tcp 5989 system_u:object_r:pegasus_https_port_t:s0
+portcon tcp 106 system_u:object_r:pop_port_t:s0
+portcon tcp 109 system_u:object_r:pop_port_t:s0
+portcon tcp 110 system_u:object_r:pop_port_t:s0
+portcon tcp 143 system_u:object_r:pop_port_t:s0
+portcon tcp 220 system_u:object_r:pop_port_t:s0
+portcon tcp 993 system_u:object_r:pop_port_t:s0
+portcon tcp 995 system_u:object_r:pop_port_t:s0
+portcon tcp 1109 system_u:object_r:pop_port_t:s0
+portcon udp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 111 system_u:object_r:portmap_port_t:s0
+portcon tcp 5432 system_u:object_r:postgresql_port_t:s0
+portcon tcp 60000 system_u:object_r:postgrey_port_t:s0
+portcon tcp 515 system_u:object_r:printer_port_t:s0
+portcon tcp 5703 system_u:object_r:ptal_port_t:s0
+portcon udp 4011 system_u:object_r:pxe_port_t:s0
+portcon udp 24441 system_u:object_r:pyzor_port_t:s0
+portcon udp 1646 system_u:object_r:radacct_port_t:s0
+portcon udp 1813 system_u:object_r:radacct_port_t:s0
+portcon udp 1645 system_u:object_r:radius_port_t:s0
+portcon udp 1812 system_u:object_r:radius_port_t:s0
+portcon tcp 2703 system_u:object_r:razor_port_t:s0
+portcon tcp 513 system_u:object_r:rlogind_port_t:s0
+portcon tcp 953 system_u:object_r:rndc_port_t:s0
+portcon udp 520 system_u:object_r:router_port_t:s0
+portcon tcp 514 system_u:object_r:rsh_port_t:s0
+portcon tcp 873 system_u:object_r:rsync_port_t:s0
+portcon udp 873 system_u:object_r:rsync_port_t:s0
+portcon tcp 137-139 system_u:object_r:smbd_port_t:s0
+portcon tcp 445 system_u:object_r:smbd_port_t:s0
+portcon tcp 25 system_u:object_r:smtp_port_t:s0
+portcon tcp 465 system_u:object_r:smtp_port_t:s0
+portcon tcp 587 system_u:object_r:smtp_port_t:s0
+portcon udp 161 system_u:object_r:snmp_port_t:s0
+portcon udp 162 system_u:object_r:snmp_port_t:s0
+portcon tcp 199 system_u:object_r:snmp_port_t:s0
+portcon tcp 783 system_u:object_r:spamd_port_t:s0
+portcon tcp 22 system_u:object_r:ssh_port_t:s0
+portcon tcp 8000 system_u:object_r:soundd_port_t:s0
+portcon tcp 9433 system_u:object_r:soundd_port_t:s0
+portcon tcp 901 system_u:object_r:swat_port_t:s0
+portcon udp 514 system_u:object_r:syslogd_port_t:s0
+portcon tcp 23 system_u:object_r:telnetd_port_t:s0
+portcon udp 69 system_u:object_r:tftp_port_t:s0
+portcon tcp 8081 system_u:object_r:transproxy_port_t:s0
+portcon tcp 540 system_u:object_r:uucpd_port_t:s0
+portcon tcp 5900 system_u:object_r:vnc_port_t:s0
+portcon tcp 6001 system_u:object_r:xserver_port_t:s0
+portcon tcp 6002 system_u:object_r:xserver_port_t:s0
+portcon tcp 6003 system_u:object_r:xserver_port_t:s0
+portcon tcp 6004 system_u:object_r:xserver_port_t:s0
+portcon tcp 6005 system_u:object_r:xserver_port_t:s0
+portcon tcp 6006 system_u:object_r:xserver_port_t:s0
+portcon tcp 6007 system_u:object_r:xserver_port_t:s0
+portcon tcp 6008 system_u:object_r:xserver_port_t:s0
+portcon tcp 6009 system_u:object_r:xserver_port_t:s0
+portcon tcp 6010 system_u:object_r:xserver_port_t:s0
+portcon tcp 6011 system_u:object_r:xserver_port_t:s0
+portcon tcp 6012 system_u:object_r:xserver_port_t:s0
+portcon tcp 6013 system_u:object_r:xserver_port_t:s0
+portcon tcp 6014 system_u:object_r:xserver_port_t:s0
+portcon tcp 6015 system_u:object_r:xserver_port_t:s0
+portcon tcp 6016 system_u:object_r:xserver_port_t:s0
+portcon tcp 6017 system_u:object_r:xserver_port_t:s0
+portcon tcp 6018 system_u:object_r:xserver_port_t:s0
+portcon tcp 6019 system_u:object_r:xserver_port_t:s0
+portcon tcp 8002 system_u:object_r:xen_port_t:s0
+portcon tcp 2601 system_u:object_r:zebra_port_t:s0
+portcon tcp 8021 system_u:object_r:zope_port_t:s0
+portcon tcp 1-1023 system_u:object_r:reserved_port_t:s0
+portcon udp 1-1023 system_u:object_r:reserved_port_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:compat_ipv4_node_t:s0
+nodecon 0.0.0.0 255.255.255.255 system_u:object_r:inaddr_any_node_t:s0
+nodecon fe80:: ffff:ffff:ffff:ffff:: system_u:object_r:link_local_node_t:s0
+nodecon 127.0.0.1 255.255.255.255 system_u:object_r:lo_node_t:s0
+nodecon ::ffff:0000:0000 ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:mapped_ipv4_node_t:s0
+nodecon ff00:: ff00:: system_u:object_r:multicast_node_t:s0
+nodecon fec0:: ffc0:: system_u:object_r:site_local_node_t:s0
+nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system_u:object_r:unspec_node_t:s0
diff --git a/libsepol/tests/policies/test-deps/base-metreq.conf b/libsepol/tests/policies/test-deps/base-metreq.conf
new file mode 100644
index 0000000..bfb4c56
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/base-metreq.conf
@@ -0,0 +1,523 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+
+# Make this decl easy to find
+type base_global_decl_t;
+
+# Actually used in module tests
+type type_req_t;
+attribute attr_req;
+bool bool_req false;
+role role_req_r;
+
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-deps/base-notmetreq.conf b/libsepol/tests/policies/test-deps/base-notmetreq.conf
new file mode 100644
index 0000000..f2630e7
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/base-notmetreq.conf
@@ -0,0 +1,510 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-deps/modreq-attr-global.conf b/libsepol/tests/policies/test-deps/modreq-attr-global.conf
new file mode 100644
index 0000000..92f6b30
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-attr-global.conf
@@ -0,0 +1,10 @@
+module modreq_attr_global 1.0;
+
+require {
+ attribute attr_req;
+}
+
+type mod_global_t;
+
+type new_t, attr_req;
+
diff --git a/libsepol/tests/policies/test-deps/modreq-attr-opt.conf b/libsepol/tests/policies/test-deps/modreq-attr-opt.conf
new file mode 100644
index 0000000..b970c1d
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-attr-opt.conf
@@ -0,0 +1,16 @@
+module modreq_attr_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ attribute attr_req;
+ }
+ type mod_opt_t;
+ type new_t, attr_req;
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-bool-global.conf b/libsepol/tests/policies/test-deps/modreq-bool-global.conf
new file mode 100644
index 0000000..4ef0cc9
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-bool-global.conf
@@ -0,0 +1,15 @@
+module modreq_bool_global 1.0;
+
+require {
+ bool bool_req;
+ class file { read write };
+}
+
+type mod_global_t;
+
+type a_t;
+type b_t;
+
+if (bool_req) {
+ allow a_t b_t : file { read write };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-bool-opt.conf b/libsepol/tests/policies/test-deps/modreq-bool-opt.conf
new file mode 100644
index 0000000..27af4f2
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-bool-opt.conf
@@ -0,0 +1,22 @@
+module modreq_bool_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ bool bool_req;
+ }
+
+ type a_t;
+ type b_t;
+ type mod_opt_t;
+
+ if (bool_req) {
+ allow a_t b_t : file { read write };
+ }
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-obj-global.conf b/libsepol/tests/policies/test-deps/modreq-obj-global.conf
new file mode 100644
index 0000000..e9eba77
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-obj-global.conf
@@ -0,0 +1,13 @@
+module modreq_obj_global 1.0;
+
+require {
+ class sem { create destroy };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+allow mod_foo_t mod_bar_t : sem { create destroy };
+
diff --git a/libsepol/tests/policies/test-deps/modreq-obj-opt.conf b/libsepol/tests/policies/test-deps/modreq-obj-opt.conf
new file mode 100644
index 0000000..67a41a4
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-obj-opt.conf
@@ -0,0 +1,20 @@
+module modreq_obj_global 1.0;
+
+require {
+ class file { read };
+}
+
+type mod_global_t;
+
+type mod_foo_t;
+type mod_bar_t;
+
+optional {
+ require {
+ class sem { create destroy };
+ }
+
+ type mod_opt_t;
+
+ allow mod_foo_t mod_bar_t : sem { create destroy };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-perm-global.conf b/libsepol/tests/policies/test-deps/modreq-perm-global.conf
new file mode 100644
index 0000000..941ca96
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-perm-global.conf
@@ -0,0 +1,10 @@
+module modreq_perm_global 1.0;
+
+require {
+ class msg { send receive };
+}
+
+type mod_global_t;
+type a_t;
+type b_t;
+allow a_t b_t: msg { send receive };
diff --git a/libsepol/tests/policies/test-deps/modreq-perm-opt.conf b/libsepol/tests/policies/test-deps/modreq-perm-opt.conf
new file mode 100644
index 0000000..43a3f97
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-perm-opt.conf
@@ -0,0 +1,18 @@
+module modreq_perm_opt 1.0;
+
+require {
+ class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ class msg { send receive };
+ }
+
+ type mod_opt_t;
+ type a_mod_t;
+ type b_mod_t;
+ allow a_mod_t b_mod_t: msg { send receive };
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-role-global.conf b/libsepol/tests/policies/test-deps/modreq-role-global.conf
new file mode 100644
index 0000000..01fd3ec
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-role-global.conf
@@ -0,0 +1,13 @@
+module modreq_role_global 1.0;
+
+require {
+ role role_req_r, user_r;
+}
+
+type mod_global_t;
+
+type a_t;
+
+# role role_req_r types a_t;
+allow role_req_r user_r;
+
diff --git a/libsepol/tests/policies/test-deps/modreq-role-opt.conf b/libsepol/tests/policies/test-deps/modreq-role-opt.conf
new file mode 100644
index 0000000..532a77e
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-role-opt.conf
@@ -0,0 +1,17 @@
+module modreq_role_opt 1.0;
+
+require {
+ class file {read write};
+
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ role role_req_r, user_r;
+ }
+ type mod_opt_t;
+
+ allow role_req_r user_r;
+}
diff --git a/libsepol/tests/policies/test-deps/modreq-type-global.conf b/libsepol/tests/policies/test-deps/modreq-type-global.conf
new file mode 100644
index 0000000..e5704a3
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-type-global.conf
@@ -0,0 +1,12 @@
+module modreq_type_global 1.0;
+
+require {
+ type type_req_t;
+ class file { read write };
+}
+
+type mod_global_t;
+
+type test_t;
+
+allow test_t type_req_t : file { read write };
diff --git a/libsepol/tests/policies/test-deps/modreq-type-opt.conf b/libsepol/tests/policies/test-deps/modreq-type-opt.conf
new file mode 100644
index 0000000..65071d7
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/modreq-type-opt.conf
@@ -0,0 +1,16 @@
+module modreq_type_opt 1.0;
+
+require {
+ type file_t;
+ class file { read write };
+}
+
+type mod_global_t;
+
+optional {
+ require {
+ type type_req_t;
+ }
+ type mod_opt_t;
+ allow type_req_t file_t : file { read write };
+}
\ No newline at end of file
diff --git a/libsepol/tests/policies/test-deps/module.conf b/libsepol/tests/policies/test-deps/module.conf
new file mode 100644
index 0000000..1971e4c
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/module.conf
@@ -0,0 +1,20 @@
+module my_module 1.0;
+
+require {
+ bool secure_mode;
+ type system_t, sysadm_t, file_t;
+ attribute domain;
+ role system_r;
+ class file {read write};
+
+}
+
+type new_t, domain;
+role system_r types new_t;
+
+allow system_t file_t : file { read write };
+
+if (secure_mode)
+{
+ allow sysadm_t file_t : file { read write };
+}
diff --git a/libsepol/tests/policies/test-deps/small-base.conf b/libsepol/tests/policies/test-deps/small-base.conf
new file mode 100644
index 0000000..7c1cbe4
--- /dev/null
+++ b/libsepol/tests/policies/test-deps/small-base.conf
@@ -0,0 +1,511 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/alias-base.conf b/libsepol/tests/policies/test-expander/alias-base.conf
new file mode 100644
index 0000000..4ed46d2
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/alias-base.conf
@@ -0,0 +1,501 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+type enable_optional;
+
+# Alias tests
+type alias_check_1_t;
+type alias_check_2_t;
+type alias_check_3_t;
+
+typealias alias_check_1_t alias alias_check_1_a;
+
+optional {
+ require {
+ type alias_check_2_t;
+ }
+ typealias alias_check_2_t alias alias_check_2_a;
+}
+
+optional {
+ require {
+ type alias_check_3_a;
+ }
+ allow alias_check_3_a enable_optional:file read;
+}
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/alias-module.conf b/libsepol/tests/policies/test-expander/alias-module.conf
new file mode 100644
index 0000000..72d791e
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/alias-module.conf
@@ -0,0 +1,8 @@
+module my_module 1.0;
+
+require {
+ type alias_check_3_t;
+}
+
+typealias alias_check_3_t alias alias_check_3_a;
+
diff --git a/libsepol/tests/policies/test-expander/base-base-only.conf b/libsepol/tests/policies/test-expander/base-base-only.conf
new file mode 100644
index 0000000..4eae73e
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/base-base-only.conf
@@ -0,0 +1,44 @@
+class security
+class file
+
+sid kernel
+
+common file
+{
+ read
+}
+
+class file
+inherits file
+{
+ entrypoint
+}
+
+class security
+{
+ compute_av
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+dominance { s0 }
+
+category c0;
+
+level s0:c0;
+
+mlsconstrain file { read }
+ ( h1 dom h2 );
+')
+
+attribute myattr;
+type mytype_t;
+role myrole_r;
+role myrole_r types mytype_t;
+bool mybool true;
+gen_user(myuser_u,, myrole_r, s0, s0 - s0:c0)
+
+sid kernel gen_context(myuser_u:myrole_r:mytype_t, s0)
+
+
diff --git a/libsepol/tests/policies/test-expander/module.conf b/libsepol/tests/policies/test-expander/module.conf
new file mode 100644
index 0000000..6186db7
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/module.conf
@@ -0,0 +1,228 @@
+module my_module 1.0;
+
+require {
+ bool allow_ypbind, secure_mode, allow_execstack;
+ type system_t, sysadm_t;
+ class file {read write};
+ attribute attr_check_base_2, attr_check_base_3;
+ attribute attr_check_base_optional_2;
+}
+
+bool module_1_bool true;
+
+if (module_1_bool && allow_ypbind && secure_mode && allow_execstack) {
+ allow system_t sysadm_t : file { read write };
+}
+
+optional {
+ bool module_1_bool_2 false;
+ require {
+ bool optional_bool_1, optional_bool_2;
+ class file { execute ioctl };
+ }
+ if (optional_bool_1 && optional_bool_2 || module_1_bool_2) {
+ allow system_t sysadm_t : file {execute ioctl};
+ }
+}
+# Type - attribute mapping test
+type module_t;
+attribute attr_check_mod_1;
+attribute attr_check_mod_2;
+attribute attr_check_mod_3;
+attribute attr_check_mod_4;
+attribute attr_check_mod_5;
+attribute attr_check_mod_6;
+attribute attr_check_mod_7;
+attribute attr_check_mod_8;
+attribute attr_check_mod_9;
+attribute attr_check_mod_10;
+attribute attr_check_mod_11;
+optional {
+ require {
+ type base_t;
+ }
+ attribute attr_check_mod_optional_1;
+ attribute attr_check_mod_optional_2;
+ attribute attr_check_mod_optional_3;
+ attribute attr_check_mod_optional_4;
+ attribute attr_check_mod_optional_5;
+ attribute attr_check_mod_optional_6;
+ attribute attr_check_mod_optional_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ attribute attr_check_mod_optional_disabled_4;
+ attribute attr_check_mod_optional_disabled_7;
+}
+type attr_check_base_2_1_t, attr_check_base_2;
+type attr_check_base_2_2_t;
+typeattribute attr_check_base_2_2_t attr_check_base_2;
+type attr_check_base_3_3_t, attr_check_base_3;
+type attr_check_base_3_4_t;
+typeattribute attr_check_base_3_4_t attr_check_base_3;
+optional {
+ require {
+ attribute attr_check_base_5;
+ }
+ type attr_check_base_5_1_t, attr_check_base_5;
+ type attr_check_base_5_2_t;
+ typeattribute attr_check_base_5_2_t attr_check_base_5;
+}
+optional {
+ require {
+ attribute attr_check_base_6;
+ }
+ type attr_check_base_6_3_t, attr_check_base_6;
+ type attr_check_base_6_4_t;
+ typeattribute attr_check_base_6_4_t attr_check_base_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_8;
+ }
+ type attr_check_base_8_1_t, attr_check_base_8;
+ type attr_check_base_8_2_t;
+ typeattribute attr_check_base_8_2_t attr_check_base_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_9;
+ }
+ type attr_check_base_9_3_t, attr_check_base_9;
+ type attr_check_base_9_4_t;
+ typeattribute attr_check_base_9_4_t attr_check_base_9;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_10;
+ }
+ type attr_check_base_10_3_t, attr_check_base_10;
+ type attr_check_base_10_4_t;
+ typeattribute attr_check_base_10_4_t attr_check_base_10;
+}
+optional {
+ require {
+ attribute attr_check_base_11;
+ }
+ type attr_check_base_11_3_t, attr_check_base_11;
+ type attr_check_base_11_4_t;
+ typeattribute attr_check_base_11_4_t attr_check_base_11;
+}
+type attr_check_base_optional_2_1_t, attr_check_base_optional_2;
+type attr_check_base_optional_2_2_t;
+typeattribute attr_check_base_optional_2_2_t attr_check_base_optional_2;
+optional {
+ require {
+ attribute attr_check_base_optional_5;
+ }
+ type attr_check_base_optional_5_1_t, attr_check_base_optional_5;
+ type attr_check_base_optional_5_2_t;
+ typeattribute attr_check_base_optional_5_2_t attr_check_base_optional_5;
+}
+#optional {
+# require {
+# attribute attr_check_base_optional_6;
+# }
+# type attr_check_base_optional_6_3_t, attr_check_base_optional_6;
+# type attr_check_base_optional_6_4_t;
+# typeattribute attr_check_base_optional_6_4_t attr_check_base_optional_6;
+#}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_optional_8;
+ }
+ type attr_check_base_optional_8_1_t, attr_check_base_optional_8;
+ type attr_check_base_optional_8_2_t;
+ typeattribute attr_check_base_optional_8_2_t attr_check_base_optional_8;
+}
+type attr_check_mod_2_1_t, attr_check_mod_2;
+type attr_check_mod_2_2_t;
+typeattribute attr_check_mod_2_2_t attr_check_mod_2;
+optional {
+ require {
+ attribute attr_check_mod_5;
+ }
+ type attr_check_mod_5_1_t, attr_check_mod_5;
+ type attr_check_mod_5_2_t;
+ typeattribute attr_check_mod_5_2_t attr_check_mod_5;
+}
+optional {
+ require {
+ attribute attr_check_mod_6;
+ }
+ type attr_check_mod_6_3_t, attr_check_mod_6;
+ type attr_check_mod_6_4_t;
+ typeattribute attr_check_mod_6_4_t attr_check_mod_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_8_1_t, attr_check_mod_8;
+ type attr_check_mod_8_2_t;
+ typeattribute attr_check_mod_8_2_t attr_check_mod_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_9_3_t, attr_check_mod_9;
+ type attr_check_mod_9_4_t;
+ typeattribute attr_check_mod_9_4_t attr_check_mod_9;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_mod_10_3_t, attr_check_mod_10;
+ type attr_check_mod_10_4_t;
+ typeattribute attr_check_mod_10_4_t attr_check_mod_10;
+}
+optional {
+ require {
+ type base_t;
+ }
+ type attr_check_mod_11_3_t, attr_check_mod_11;
+ type attr_check_mod_11_4_t;
+ typeattribute attr_check_mod_11_4_t attr_check_mod_11;
+}
+#optional {
+# require {
+# attribute attr_check_mod_optional_5;
+# }
+# type attr_check_mod_optional_5_1_t, attr_check_mod_optional_5;
+# type attr_check_mod_optional_5_2_t;
+# typeattribute attr_check_mod_optional_5_2_t attr_check_mod_optional_5;
+#}
+#optional {
+# require {
+# attribute attr_check_mod_optional_6;
+# }
+# type attr_check_mod_optional_6_3_t, attr_check_mod_optional_6;
+# type attr_check_mod_optional_6_4_t;
+# typeattribute attr_check_mod_optional_6_4_t attr_check_mod_optional_6;
+#}
+optional {
+ require {
+ attribute attr_check_base_optional_disabled_5;
+ }
+ type attr_check_base_optional_disabled_5_1_t, attr_check_base_optional_disabled_5;
+ type attr_check_base_optional_disabled_5_2_t;
+ typeattribute attr_check_base_optional_disabled_5_2_t attr_check_base_optional_disabled_5;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_base_optional_disabled_8;
+ }
+ type attr_check_base_optional_disabled_8_1_t, attr_check_base_optional_disabled_8;
+ type attr_check_base_optional_disabled_8_2_t;
+ typeattribute attr_check_base_optional_disabled_8_2_t attr_check_base_optional_disabled_8;
+}
+
diff --git a/libsepol/tests/policies/test-expander/role-base.conf b/libsepol/tests/policies/test-expander/role-base.conf
new file mode 100644
index 0000000..b43389f
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/role-base.conf
@@ -0,0 +1,483 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+# Role mapping test
+type role_check_1_1_t;
+role role_check_1;
+role role_check_1 types role_check_1_1_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/role-module.conf b/libsepol/tests/policies/test-expander/role-module.conf
new file mode 100644
index 0000000..1cc5d22
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/role-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require {
+ class file {read write};
+ role role_check_1;
+}
+
+type role_check_1_2_t;
+role role_check_1 types role_check_1_2_t;
diff --git a/libsepol/tests/policies/test-expander/small-base.conf b/libsepol/tests/policies/test-expander/small-base.conf
new file mode 100644
index 0000000..7c5d77a
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/small-base.conf
@@ -0,0 +1,721 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+# TE RULES
+attribute domain;
+attribute system;
+attribute foo;
+attribute num;
+attribute num_exec;
+attribute files;
+
+# Type - attribute mapping test
+# Shorthand tests
+# 1 = types in base, 2 = types in mod, 3 = types in both
+# 4 = types in optional in base, 5 = types in optional in mod
+# 6 = types in optional in both
+# 7 = types in disabled optional in base
+# 8 = types in disabled optional in module
+# 9 = types in disabled optional in both
+# 10 = types in enabled optional in base, disabled optional in module
+# 11 = types in disabled optional in base, enabled optional in module
+attribute attr_check_base_1;
+attribute attr_check_base_2;
+attribute attr_check_base_3;
+attribute attr_check_base_4;
+attribute attr_check_base_5;
+attribute attr_check_base_6;
+attribute attr_check_base_7;
+attribute attr_check_base_8;
+attribute attr_check_base_9;
+attribute attr_check_base_10;
+attribute attr_check_base_11;
+optional {
+ require {
+ type module_t;
+ }
+ attribute attr_check_base_optional_1;
+ attribute attr_check_base_optional_2;
+ attribute attr_check_base_optional_3;
+ attribute attr_check_base_optional_4;
+ attribute attr_check_base_optional_5;
+ attribute attr_check_base_optional_6;
+ attribute attr_check_base_optional_8;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ attribute attr_check_base_optional_disabled_5;
+ attribute attr_check_base_optional_disabled_8;
+}
+
+type net_foo_t, foo;
+type sys_foo_t, foo, system;
+role system_r;
+role system_r types sys_foo_t;
+
+type user_t, domain;
+role user_r;
+role user_r types user_t;
+
+type sysadm_t, domain, system;
+role sysadm_r;
+role sysadm_r types sysadm_t;
+
+type system_t, domain, system, foo;
+role system_r types { system_t sys_foo_t };
+
+type file_t;
+type file_exec_t, files;
+type fs_t;
+type base_optional_1;
+type base_optional_2;
+
+allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint };
+
+optional {
+ require {
+ type base_optional_1, base_optional_2;
+ }
+ allow base_optional_1 base_optional_2 : file { read write };
+}
+
+# Type - attribute mapping test
+type base_t;
+type attr_check_base_1_1_t, attr_check_base_1;
+type attr_check_base_1_2_t;
+typeattribute attr_check_base_1_2_t attr_check_base_1;
+type attr_check_base_3_1_t, attr_check_base_3;
+type attr_check_base_3_2_t;
+typeattribute attr_check_base_3_2_t attr_check_base_3;
+optional {
+ require {
+ attribute attr_check_base_4;
+ }
+ type attr_check_base_4_1_t, attr_check_base_4;
+ type attr_check_base_4_2_t;
+ typeattribute attr_check_base_4_2_t attr_check_base_4;
+}
+optional {
+ require {
+ type module_t;
+ }
+ type attr_check_base_6_1_t, attr_check_base_6;
+ type attr_check_base_6_2_t;
+ typeattribute attr_check_base_6_2_t attr_check_base_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_7_1_t, attr_check_base_7;
+ type attr_check_base_7_2_t;
+ typeattribute attr_check_base_7_2_t attr_check_base_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_9_1_t, attr_check_base_9;
+ type attr_check_base_9_2_t;
+ typeattribute attr_check_base_9_2_t attr_check_base_9;
+}
+optional {
+ require {
+ type module_t;
+ }
+ type attr_check_base_10_1_t, attr_check_base_10;
+ type attr_check_base_10_2_t;
+ typeattribute attr_check_base_10_2_t attr_check_base_10;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ }
+ type attr_check_base_11_1_t, attr_check_base_11;
+ type attr_check_base_11_2_t;
+ typeattribute attr_check_base_11_2_t attr_check_base_11;
+}
+#optional {
+# require {
+# attribute attr_check_base_optional_4;
+# }
+# type attr_check_base_optional_4_1_t, attr_check_base_optional_4;
+# type attr_check_base_optional_4_2_t;
+# typeattribute attr_check_base_optional_4_2_t attr_check_base_optional_4;
+#}
+#optional {
+# require {
+# attribute attr_check_base_optional_6;
+# }
+# type attr_check_base_optional_6_1_t, attr_check_base_optional_6;
+# type attr_check_base_optional_6_2_t;
+# typeattribute attr_check_base_optional_6_2_t attr_check_base_optional_6;
+#}
+optional {
+ require {
+ attribute attr_check_mod_4;
+ }
+ type attr_check_mod_4_1_t, attr_check_mod_4;
+ type attr_check_mod_4_2_t;
+ typeattribute attr_check_mod_4_2_t attr_check_mod_4;
+}
+optional {
+ require {
+ attribute attr_check_mod_6;
+ }
+ type attr_check_mod_6_1_t, attr_check_mod_6;
+ type attr_check_mod_6_2_t;
+ typeattribute attr_check_mod_6_2_t attr_check_mod_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_7;
+ }
+ type attr_check_mod_7_1_t, attr_check_mod_7;
+ type attr_check_mod_7_2_t;
+ typeattribute attr_check_mod_7_2_t attr_check_mod_7;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_9;
+ }
+ type attr_check_mod_9_1_t, attr_check_mod_9;
+ type attr_check_mod_9_2_t;
+ typeattribute attr_check_mod_9_2_t attr_check_mod_9;
+}
+optional {
+ require {
+ attribute attr_check_mod_10;
+ }
+ type attr_check_mod_10_1_t, attr_check_mod_10;
+ type attr_check_mod_10_2_t;
+ typeattribute attr_check_mod_10_2_t attr_check_mod_10;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_11;
+ }
+ type attr_check_mod_11_1_t, attr_check_mod_11;
+ type attr_check_mod_11_2_t;
+ typeattribute attr_check_mod_11_2_t attr_check_mod_11;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_4;
+ }
+ type attr_check_mod_optional_4_1_t, attr_check_mod_optional_4;
+ type attr_check_mod_optional_4_2_t;
+ typeattribute attr_check_mod_optional_4_2_t attr_check_mod_optional_4;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_6;
+ }
+ type attr_check_mod_optional_6_1_t, attr_check_mod_optional_6;
+ type attr_check_mod_optional_6_2_t;
+ typeattribute attr_check_mod_optional_6_2_t attr_check_mod_optional_6;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_optional_7;
+ }
+ type attr_check_mod_optional_7_1_t, attr_check_mod_optional_7;
+ type attr_check_mod_optional_7_2_t;
+ typeattribute attr_check_mod_optional_7_2_t attr_check_mod_optional_7;
+}
+optional {
+ require {
+ attribute attr_check_mod_optional_disabled_4;
+ }
+ type attr_check_mod_optional_disabled_4_1_t, attr_check_mod_optional_disabled_4;
+ type attr_check_mod_optional_disabled_4_2_t;
+ typeattribute attr_check_mod_optional_disabled_4_2_t attr_check_mod_optional_disabled_4;
+}
+optional {
+ require {
+ type does_not_exist_t;
+ attribute attr_check_mod_optional_disabled_7;
+ }
+ type attr_check_mod_optional_disabled_7_1_t, attr_check_mod_optional_disabled_7;
+ type attr_check_mod_optional_disabled_7_2_t;
+ typeattribute attr_check_mod_optional_disabled_7_2_t attr_check_mod_optional_disabled_7;
+}
+
+#####################################
+# Role Allow
+allow user_r sysadm_r;
+
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:sys_foo_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/user-base.conf b/libsepol/tests/policies/test-expander/user-base.conf
new file mode 100644
index 0000000..b60672f
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/user-base.conf
@@ -0,0 +1,487 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+# User mapping test
+type user_check_1_1_t;
+type user_check_1_2_t;
+role user_check_1_1_r;
+role user_check_1_2_r;
+role user_check_1_1_r types user_check_1_1_t;
+role user_check_1_2_r types user_check_1_2_t;
+
+########
+type fs_t;
+type system_t;
+type user_t;
+role system_r;
+role user_r;
+role sysadm_r;
+role system_r types system_t;
+role user_r types user_t;
+role sysadm_r types system_t;
+####################################
+# Booleans
+bool allow_ypbind true;
+bool secure_mode false;
+bool allow_execheap false;
+bool allow_execmem true;
+bool allow_execmod false;
+bool allow_execstack true;
+bool optional_bool_1 true;
+bool optional_bool_2 false;
+
+#####################################
+# users
+gen_user(user_check_1,, user_check_1_1_r user_check_1_2_r, s0, s0 - s0:c0.c23)
+gen_user(system_u,, system_r, s0, s0 - s0:c0.c23)
+gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23)
+gen_user(joe,, user_r, s0, s0 - s0:c0.c23)
+
+#####################################
+# constraints
+
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(system_u:system_r:system_t, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0);
+fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0);
+
+
+genfscon proc / gen_context(system_u:object_r:system_t, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 system_u:object_r:net_foo_t:s0
+
+#netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-expander/user-module.conf b/libsepol/tests/policies/test-expander/user-module.conf
new file mode 100644
index 0000000..4ef3e62
--- /dev/null
+++ b/libsepol/tests/policies/test-expander/user-module.conf
@@ -0,0 +1,9 @@
+module my_module 1.0;
+
+require {
+ class file {read write};
+ifdef(`enable_mls',`
+ user user_check_1;
+')
+}
+
diff --git a/libsepol/tests/policies/test-hooks/cmp_policy.conf b/libsepol/tests/policies/test-hooks/cmp_policy.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/cmp_policy.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+ require {
+ type invalid_type;
+ }
+ allow g_b_role_2 g_b_role_3;
+ role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf b/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf
new file mode 100644
index 0000000..c6ecd83
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/module_add_role_allow_trans.conf
@@ -0,0 +1,15 @@
+module add_symbol_test 1.0;
+
+require { class file { read }; }
+
+role role_a_1;
+role role_a_2;
+role role_t_1;
+role role_t_2;
+
+type type_rt_1;
+
+
+allow role_a_1 role_a_2;
+
+role_transition role_t_1 type_rt_1 role_t_2;
diff --git a/libsepol/tests/policies/test-hooks/module_add_symbols.conf b/libsepol/tests/policies/test-hooks/module_add_symbols.conf
new file mode 100644
index 0000000..cf56e18
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/module_add_symbols.conf
@@ -0,0 +1,12 @@
+module add_symbol_test 1.0;
+
+require { class file { read write }; }
+
+type type_add_1;
+attribute attrib_add_1;
+role role_add_1;
+bool bool_add_1 false;
+
+ifdef(`enable_mls',`',`
+user user_add_1 roles { role_add_1 };
+')
diff --git a/libsepol/tests/policies/test-hooks/small-base.conf b/libsepol/tests/policies/test-hooks/small-base.conf
new file mode 100644
index 0000000..ec1e234
--- /dev/null
+++ b/libsepol/tests/policies/test-hooks/small-base.conf
@@ -0,0 +1,471 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type g_b_type_1;
+role g_b_role_1 types g_b_type_1;
+
+role g_b_role_2 types g_b_type_1;
+role g_b_role_3 types g_b_type_1;
+type g_b_type_2;
+
+optional {
+ require {
+ type invalid_type;
+ }
+ allow g_b_role_2 g_b_role_3;
+ role_transition g_b_role_2 g_b_type_2 g_b_role_3;
+}
+
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/policies/test-linker/module1.conf b/libsepol/tests/policies/test-linker/module1.conf
new file mode 100644
index 0000000..2d5fc31
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/module1.conf
@@ -0,0 +1,145 @@
+module linker_test_1 1.0;
+
+require {
+ class file { read write };
+ class lnk_file append;
+ role g_b_role_2;
+ attribute g_b_attr_3;
+ attribute g_b_attr_5;
+ attribute o4_b_attr_1;
+ type g_b_type_3;
+}
+
+type tag_g_m1;
+
+#test for type in module and attr in module, added to in module
+attribute g_m1_attr_1;
+type g_m1_type_1, g_m1_attr_1;
+type g_m1_type_2;
+typeattribute g_m1_type_2 g_m1_attr_1;
+
+#add role in module test
+role g_m1_role_1;
+role g_m1_role_1 types g_m1_type_1;
+
+# test for attr declared in base, added to in module
+type g_m1_type_3;
+typeattribute g_m1_type_3 g_b_attr_3;
+
+# test for attr declared in base, added to in 2 modules
+type g_m1_type_4;
+typeattribute g_m1_type_4 g_b_attr_5;
+
+# test for attr declared in base optional, added to in module
+type g_m1_type_5;
+typeattribute g_m1_type_5 o4_b_attr_1;
+
+# test for attr declared in module, added to in base optional
+attribute g_m1_attr_2;
+
+#add type to base role test
+role g_b_role_2 types g_m1_type_1;
+role g_b_role_3;
+role g_b_role_3 types g_m1_type_2;
+
+#add type to base optional role test
+role o1_b_role_2;
+role o1_b_role_2 types g_m1_type_1;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1;
+role o4_b_role_1 types g_m1_type_2;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+attribute g_m1_attr_3;
+type g_m1_type_6, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module , added to in other module optional
+attribute g_m1_attr_4;
+type g_m1_type_7, g_m1_attr_4;
+
+# alias tests
+typealias g_b_type_3 alias g_m_alias_1;
+
+# single boolean in module
+bool g_m1_bool_1 true;
+if (g_m1_bool_1) {
+ allow g_m1_type_1 g_m1_type_2 : lnk_file append;
+}
+
+
+optional {
+ require {
+ type optional_type;
+ attribute g_b_attr_4;
+ attribute o1_b_attr_2;
+ class lnk_file { ioctl };
+ }
+
+ type tag_o1_m1;
+
+ attribute o1_m1_attr_1;
+ type o1_m1_type_2, o1_m1_attr_1;
+
+ type o1_m1_type_1;
+ role o1_m1_role_1;
+ role o1_m1_role_1 types o1_m1_type_1;
+
+ type o1_m1_type_3;
+ typeattribute o1_m1_type_3 g_b_attr_4;
+
+ type o1_m1_type_5;
+ typeattribute o1_m1_type_5 o1_b_attr_2;
+
+ bool o1_m1_bool_1 false;
+ if (o1_m1_bool_1) {
+ allow o1_m1_type_2 o1_m1_type_1 : lnk_file ioctl;
+ }
+
+}
+
+optional {
+ require {
+ type optional_type;
+ #role g_b_role_4; // This causes a bug where the role scope doesn't get copied into base
+ }
+
+ type tag_o2_m1;
+
+ role g_b_role_4;
+ role g_b_role_4 types g_m1_type_2;
+}
+
+optional {
+ require {
+ attribute g_b_attr_6;
+ }
+
+ type tag_o3_m1;
+
+ type o3_m1_type_1;
+ role o3_b_role_1;
+ role o3_b_role_1 types o3_m1_type_1;
+
+ type o3_m1_type_2, g_b_attr_6;
+
+ attribute o3_m1_attr_1;
+
+ # attr a added to in base optional, declared/added in module optional, added to in other module
+ attribute o3_m1_attr_2;
+ type o3_m1_type_3, o3_m1_attr_2;
+
+}
+
+optional {
+ require {
+ type enable_optional;
+ }
+ type tag_o4_m1;
+
+ attribute o4_m1_attr_1;
+ type o4_m1_type_1;
+ typeattribute o4_m1_type_1 o4_m1_attr_1;
+
+
+}
diff --git a/libsepol/tests/policies/test-linker/module2.conf b/libsepol/tests/policies/test-linker/module2.conf
new file mode 100644
index 0000000..7a31109
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/module2.conf
@@ -0,0 +1,66 @@
+module linker_test_2 1.0;
+
+require {
+ class file { read write };
+ class lnk_file { unlink };
+ attribute g_b_attr_5;
+ attribute g_b_attr_6;
+ attribute g_m1_attr_3;
+ attribute o3_m1_attr_2;
+}
+
+type tag_g_m2;
+
+type g_m2_type_1;
+role g_m2_role_1;
+role g_m2_role_1 types g_m2_type_1;
+
+type g_m2_type_4, g_b_attr_5;
+type g_m2_type_5, g_b_attr_6;
+
+#add types to role declared in base test
+type g_m2_type_2;
+role g_b_role_3;
+role g_b_role_3 types g_m2_type_2;
+
+#optional base role w/ adds in 2 modules
+role o4_b_role_1;
+role o4_b_role_1 types g_m2_type_1;
+
+# attr a added to in base optional, declared/added to in module, added to in other module
+type g_m2_type_3, g_m1_attr_3;
+
+# attr a added to in base optional, declared/added in module optional, added to in other module
+type g_m2_type_6, o3_m1_attr_2;
+
+# cond mapping tests
+bool g_m2_bool_1 true;
+bool g_m2_bool_2 false;
+if (g_m2_bool_1 && g_m2_bool_2) {
+ allow g_m2_type_1 g_m2_type_2 : lnk_file unlink;
+}
+
+optional {
+ require {
+ type optional_type;
+ }
+
+ type tag_o1_m2;
+
+ type o1_m2_type_1;
+ role o1_m2_role_1;
+ role o1_m2_role_1 types o1_m2_type_1;
+}
+
+
+optional {
+ require {
+ attribute g_m1_attr_4;
+ attribute o4_m1_attr_1;
+ }
+ type tag_o2_m2;
+
+ type o2_m2_type_1, g_m1_attr_4;
+ type o2_m2_type_2, o4_m1_attr_1;
+
+}
diff --git a/libsepol/tests/policies/test-linker/small-base.conf b/libsepol/tests/policies/test-linker/small-base.conf
new file mode 100644
index 0000000..3a66f91
--- /dev/null
+++ b/libsepol/tests/policies/test-linker/small-base.conf
@@ -0,0 +1,600 @@
+# FLASK
+
+#
+# Define the security object classes
+#
+
+class security
+class process
+class system
+class capability
+
+# file-related classes
+class filesystem
+class file
+class dir
+class fd
+class lnk_file
+class chr_file
+class blk_file
+class sock_file
+class fifo_file
+
+# network-related classes
+class socket
+class tcp_socket
+class udp_socket
+class rawip_socket
+class node
+class netif
+class netlink_socket
+class packet_socket
+class key_socket
+class unix_stream_socket
+class unix_dgram_socket
+
+# sysv-ipc-related clases
+class sem
+class msg
+class msgq
+class shm
+class ipc
+
+# FLASK
+# FLASK
+
+#
+# Define initial security identifiers
+#
+
+sid kernel
+
+
+# FLASK
+#
+# Define common prefixes for access vectors
+#
+# common common_name { permission_name ... }
+
+
+#
+# Define a common prefix for file access vectors.
+#
+
+common file
+{
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+ unlink
+ link
+ rename
+ execute
+ swapon
+ quotaon
+ mounton
+}
+
+
+#
+# Define a common prefix for socket access vectors.
+#
+
+common socket
+{
+# inherited from file
+ ioctl
+ read
+ write
+ create
+ getattr
+ setattr
+ lock
+ relabelfrom
+ relabelto
+ append
+# socket-specific
+ bind
+ connect
+ listen
+ accept
+ getopt
+ setopt
+ shutdown
+ recvfrom
+ sendto
+ recv_msg
+ send_msg
+ name_bind
+}
+
+#
+# Define a common prefix for ipc access vectors.
+#
+
+common ipc
+{
+ create
+ destroy
+ getattr
+ setattr
+ read
+ write
+ associate
+ unix_read
+ unix_write
+}
+
+#
+# Define the access vectors.
+#
+# class class_name [ inherits common_name ] { permission_name ... }
+
+
+#
+# Define the access vector interpretation for file-related objects.
+#
+
+class filesystem
+{
+ mount
+ remount
+ unmount
+ getattr
+ relabelfrom
+ relabelto
+ transition
+ associate
+ quotamod
+ quotaget
+}
+
+class dir
+inherits file
+{
+ add_name
+ remove_name
+ reparent
+ search
+ rmdir
+}
+
+class file
+inherits file
+{
+ execute_no_trans
+ entrypoint
+}
+
+class lnk_file
+inherits file
+
+class chr_file
+inherits file
+
+class blk_file
+inherits file
+
+class sock_file
+inherits file
+
+class fifo_file
+inherits file
+
+class fd
+{
+ use
+}
+
+
+#
+# Define the access vector interpretation for network-related objects.
+#
+
+class socket
+inherits socket
+
+class tcp_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class udp_socket
+inherits socket
+
+class rawip_socket
+inherits socket
+
+class node
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+ enforce_dest
+}
+
+class netif
+{
+ tcp_recv
+ tcp_send
+ udp_recv
+ udp_send
+ rawip_recv
+ rawip_send
+}
+
+class netlink_socket
+inherits socket
+
+class packet_socket
+inherits socket
+
+class key_socket
+inherits socket
+
+class unix_stream_socket
+inherits socket
+{
+ connectto
+ newconn
+ acceptfrom
+}
+
+class unix_dgram_socket
+inherits socket
+
+
+#
+# Define the access vector interpretation for process-related objects
+#
+
+class process
+{
+ fork
+ transition
+ sigchld # commonly granted from child to parent
+ sigkill # cannot be caught or ignored
+ sigstop # cannot be caught or ignored
+ signull # for kill(pid, 0)
+ signal # all other signals
+ ptrace
+ getsched
+ setsched
+ getsession
+ getpgid
+ setpgid
+ getcap
+ setcap
+ share
+}
+
+
+#
+# Define the access vector interpretation for ipc-related objects
+#
+
+class ipc
+inherits ipc
+
+class sem
+inherits ipc
+
+class msgq
+inherits ipc
+{
+ enqueue
+}
+
+class msg
+{
+ send
+ receive
+}
+
+class shm
+inherits ipc
+{
+ lock
+}
+
+
+#
+# Define the access vector interpretation for the security server.
+#
+
+class security
+{
+ compute_av
+ transition_sid
+ member_sid
+ sid_to_context
+ context_to_sid
+ load_policy
+ get_sids
+ change_sid
+ get_user_sids
+}
+
+
+#
+# Define the access vector interpretation for system operations.
+#
+
+class system
+{
+ ipc_info
+ avc_toggle
+ nfsd_control
+ bdflush
+ syslog_read
+ syslog_mod
+ syslog_console
+ ichsid
+}
+
+#
+# Define the access vector interpretation for controling capabilies
+#
+
+class capability
+{
+ # The capabilities are defined in include/linux/capability.h
+ # Care should be taken to ensure that these are consistent with
+ # those definitions. (Order matters)
+
+ chown
+ dac_override
+ dac_read_search
+ fowner
+ fsetid
+ kill
+ setgid
+ setuid
+ setpcap
+ linux_immutable
+ net_bind_service
+ net_broadcast
+ net_admin
+ net_raw
+ ipc_lock
+ ipc_owner
+ sys_module
+ sys_rawio
+ sys_chroot
+ sys_ptrace
+ sys_pacct
+ sys_admin
+ sys_boot
+ sys_nice
+ sys_resource
+ sys_time
+ sys_tty_config
+ mknod
+ lease
+}
+
+ifdef(`enable_mls',`
+sensitivity s0;
+
+#
+# Define the ordering of the sensitivity levels (least to greatest)
+#
+dominance { s0 }
+
+
+#
+# Define the categories
+#
+# Each category has a name and zero or more aliases.
+#
+category c0; category c1; category c2; category c3;
+category c4; category c5; category c6; category c7;
+category c8; category c9; category c10; category c11;
+category c12; category c13; category c14; category c15;
+category c16; category c17; category c18; category c19;
+category c20; category c21; category c22; category c23;
+
+level s0:c0.c23;
+
+mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom }
+ ( h1 dom h2 );
+')
+
+####################################
+####################################
+#####################################
+
+#g_b stands for global base
+
+type enable_optional;
+
+#decorative type for finding this decl, every block should have one
+type tag_g_b;
+
+attribute g_b_attr_1;
+attribute g_b_attr_2;
+attribute g_b_attr_3;
+attribute g_b_attr_4;
+attribute g_b_attr_5;
+attribute g_b_attr_6;
+
+type g_b_type_1, g_b_attr_1;
+type g_b_type_2, g_b_attr_2;
+type g_b_type_3;
+
+role g_b_role_1;
+role g_b_role_2;
+role g_b_role_3;
+role g_b_role_4;
+role g_b_role_1 types g_b_type_1;
+role g_b_role_2 types g_b_type_2;
+role g_b_role_3 types g_b_type_2;
+role g_b_role_4 types g_b_type_2;
+
+bool g_b_bool_1 false;
+bool g_b_bool_2 true;
+
+allow g_b_type_1 g_b_type_2 : security { compute_av load_policy };
+allow g_b_type_1 g_b_type_2 : file *; # test *
+allow g_b_type_1 g_b_type_2 : process ~ptrace; #test ~
+
+typealias g_b_type_3 alias g_b_alias_1;
+
+if (g_b_bool_1) {
+ allow g_b_type_1 g_b_type_2: lnk_file read;
+}
+
+
+optional {
+ require {
+ type enable_optional;
+ attribute g_m1_attr_2;
+ }
+ type tag_o1_b;
+
+ attribute o1_b_attr_1;
+ type o1_b_type_1, o1_b_attr_1;
+ bool o1_b_bool_1 true;
+ role o1_b_role_1;
+ role o1_b_role_1 types o1_b_type_1;
+ role o1_b_role_2;
+ role o1_b_role_2 types o1_b_type_1;
+
+ attribute o1_b_attr_2;
+
+ type o1_b_type_2, g_m1_attr_2;
+
+ if (o1_b_bool_1) {
+ allow o1_b_type_1 o1_b_type_2: lnk_file write;
+ }
+
+}
+
+optional {
+ require {
+ # this should be activated by module 1
+ type g_m1_type_1;
+ attribute o3_m1_attr_2;
+ }
+ type tag_o2_b;
+
+ type o2_b_type_1, o3_m1_attr_2;
+}
+
+optional {
+ require {
+ #this block should not come on
+ type invalid_type;
+ }
+ type tag_o3_b;
+
+
+ attribute o3_b_attr_1;
+ type o3_b_type_1;
+ bool o3_b_bool_1 true;
+
+ role o3_b_role_1;
+ role o3_b_role_1 types o3_b_type_1;
+
+ allow g_b_type_1 invalid_type : sem { create destroy };
+}
+
+optional {
+ require {
+ # also should be enabled by module 1
+ type enable_optional;
+ type g_m1_type_1;
+ attribute o3_m1_attr_1;
+ attribute g_m1_attr_3;
+ }
+
+ type tag_o4_b;
+
+ attribute o4_b_attr_1;
+
+ role o4_b_role_1;
+ role o4_b_role_1 types g_m1_type_1;
+
+ # test for attr declared in module optional, added to in base optional
+ type o4_b_type_1, o3_m1_attr_1;
+
+ type o4_b_type_2, g_m1_attr_3;
+}
+
+optional {
+ require {
+ attribute g_m1_attr_4;
+ attribute o4_m1_attr_1;
+ }
+ type tag_o5_b;
+
+ type o5_b_type_1, g_m1_attr_4;
+ type o5_b_type_2, o4_m1_attr_1;
+}
+
+optional {
+ require {
+ type enable_optional;
+ }
+ type tag_o6_b;
+
+ typealias g_b_type_3 alias g_b_alias_2;
+}
+
+optional {
+ require {
+ type g_m_alias_1;
+ }
+ type tag_o7_b;
+
+ allow g_m_alias_1 enable_optional:file read;
+}
+
+gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23)
+gen_user(g_b_user_2,, g_b_role_1, s0, s0 - s0:c0, c1, c3, c4, c5)
+
+####################################
+#line 1 "initial_sid_contexts"
+
+sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0)
+
+
+############################################
+#line 1 "fs_use"
+#
+fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0);
+
+
+genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+####################################
+#line 1 "net_contexts"
+
+#portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0
+
+#netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0
+
+#
+#nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0
+
+nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0)
+
+
+
+
diff --git a/libsepol/tests/test-common.c b/libsepol/tests/test-common.c
new file mode 100644
index 0000000..058b743
--- /dev/null
+++ b/libsepol/tests/test-common.c
@@ -0,0 +1,262 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This has tests that are common between test suites*/
+
+#include <sepol/policydb/avrule_block.h>
+
+#include <CUnit/Basic.h>
+
+void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len)
+{
+ scope_datum_t *scope;
+ int found;
+ unsigned int i, j;
+ /* make sure it is in global symtab */
+ if (!hashtab_search(p->symtab[sym_type].table, id)) {
+ fprintf(stderr, "symbol %s not found in table %d\n", id, sym_type);
+ CU_FAIL_FATAL();
+ }
+ /* make sure its scope is correct */
+ scope = hashtab_search(p->scope[sym_type].table, id);
+ CU_ASSERT_FATAL(scope != NULL);
+ CU_ASSERT(scope->scope == scope_type);
+ CU_ASSERT(scope->decl_ids_len == len);
+ if (scope->decl_ids_len != len)
+ fprintf(stderr, "sym %s has %d decls, %d expected\n", id, scope->decl_ids_len, len);
+ for (i = 0; i < len; i++) {
+ found = 0;
+ for (j = 0; j < len; j++) {
+ if (decls[i] == scope->decl_ids[j])
+ found++;
+ }
+ CU_ASSERT(found == 1);
+ }
+
+}
+
+static int common_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ common_datum_t *d = (common_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_COMMONS][d->s.value - 1] == (char *)key);
+ return 0;
+}
+
+static int class_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ class_datum_t *d = (class_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_CLASSES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->class_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int role_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ role_datum_t *d = (role_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_ROLES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->role_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int type_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ type_datum_t *d = (type_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ if (!d->primary)
+ return 0;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_TYPES][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->type_val_to_struct[d->s.value - 1] == d);
+
+ return 0;
+}
+
+static int user_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ user_datum_t *d = (user_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_USERS][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->user_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int cond_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ cond_bool_datum_t *d = (cond_bool_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_BOOLS][d->s.value - 1] == (char *)key);
+ CU_ASSERT(p->bool_val_to_struct[d->s.value - 1] == d);
+ return 0;
+}
+
+static int level_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ level_datum_t *d = (level_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_LEVELS][d->level->sens - 1] == (char *)key);
+ return 0;
+}
+
+static int cat_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ cat_datum_t *d = (cat_datum_t *) datum;
+ policydb_t *p = (policydb_t *) data;
+
+ CU_ASSERT(p->sym_val_to_name[SYM_CATS][d->s.value - 1] == (char *)key);
+ return 0;
+}
+
+static int (*test_index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *p) = {
+common_test_index, class_test_index, role_test_index, type_test_index, user_test_index, cond_test_index, level_test_index, cat_test_index,};
+
+void test_policydb_indexes(policydb_t * p)
+{
+ int i;
+
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_map(p->symtab[i].table, test_index_f[i], p);
+ }
+}
+
+void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor)
+{
+ type_datum_t *type, *primary;
+ unsigned int my_primary, my_flavor, my_value;
+
+ type = hashtab_search(p->p_types.table, id);
+ primary = hashtab_search(p->p_types.table, primary_id);
+
+ CU_ASSERT_PTR_NOT_NULL(type);
+ CU_ASSERT_PTR_NOT_NULL(primary);
+
+ if (type && primary) {
+ if (mode) {
+ my_flavor = type->flavor;
+ } else {
+ my_flavor = flavor;
+ }
+
+ if (my_flavor == TYPE_TYPE) {
+ my_primary = 0;
+ my_value = primary->s.value;
+ } else if (my_flavor == TYPE_ALIAS) {
+ my_primary = primary->s.value;
+ CU_ASSERT_NOT_EQUAL(type->s.value, primary->s.value);
+ my_value = type->s.value;
+ } else {
+ CU_FAIL("not an alias");
+ }
+
+ CU_ASSERT(type->primary == my_primary);
+ CU_ASSERT(type->flavor == my_flavor);
+ CU_ASSERT(type->s.value == my_value);
+ }
+}
+
+role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags)
+{
+ ebitmap_node_t *tnode;
+ unsigned int i, j, new, found = 0;
+ role_datum_t *role;
+
+ if (decl)
+ role = hashtab_search(decl->p_roles.table, id);
+ else
+ role = hashtab_search(p->p_roles.table, id);
+
+ if (!role)
+ printf("role %s can't be found! \n", id);
+
+ CU_ASSERT_FATAL(role != NULL);
+
+ ebitmap_for_each_bit(&role->types.types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ new = 0;
+ for (j = 0; j < len; j++) {
+ if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+ found++;
+ new = 1;
+ }
+ }
+ if (new == 0) {
+ printf("\nRole %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+ }
+ CU_ASSERT(new == 1);
+ }
+ }
+ CU_ASSERT(found == len);
+ if (found != len)
+ printf("\nrole %s has %d types, %d expected\n", p->sym_val_to_name[SYM_ROLES][role->s.value - 1], found, len);
+ /* roles should never have anything in the negset */
+ CU_ASSERT(role->types.negset.highbit == 0);
+ CU_ASSERT(role->types.flags == flags);
+
+ return role;
+}
+
+void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len)
+{
+ ebitmap_node_t *tnode;
+ int j, new, found = 0;
+ unsigned int i;
+ type_datum_t *attr;
+
+ if (decl)
+ attr = hashtab_search(decl->p_types.table, id);
+ else
+ attr = hashtab_search(p->p_types.table, id);
+
+ if (attr == NULL)
+ printf("could not find attr %s in decl %d\n", id, decl->decl_id);
+ CU_ASSERT_FATAL(attr != NULL);
+ CU_ASSERT(attr->flavor == TYPE_ATTRIB);
+ CU_ASSERT(attr->primary == 1);
+
+ ebitmap_for_each_bit(&attr->types, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ new = 0;
+ for (j = 0; j < len; j++) {
+ if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) {
+ found++;
+ new = 1;
+ }
+ }
+ if (new == 0) {
+ printf("\nattr %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]);
+ }
+ CU_ASSERT(new == 1);
+ }
+ }
+ CU_ASSERT(found == len);
+ if (found != len)
+ printf("\nattr %s has %d types, %d expected\n", id, found, len);
+}
diff --git a/libsepol/tests/test-common.h b/libsepol/tests/test-common.h
new file mode 100644
index 0000000..5a1e650
--- /dev/null
+++ b/libsepol/tests/test-common.h
@@ -0,0 +1,78 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_COMMON_H__
+#define __TEST_COMMON_H__
+
+#include <sepol/policydb/policydb.h>
+
+/* p the policy being inspected
+ * id string symbol identifier
+ * sym_type symbol type (eg., SYM_ROLES, SYM_TYPES)
+ * scope_type what scope the role should have (eg., SCOPE_DECL or SCOPE_REQ)
+ * decls integer array of decl id's that we expect the role to have in the scope table
+ * len number of elements in decls
+ *
+ * This is a utility function to test for the symbol's presence in the global symbol table,
+ * the scope table, and that the decl blocks we think this symbol is in are correct
+ */
+extern void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len);
+
+/* Test the indexes in the policydb to ensure their correctness. These include
+ * the sym_val_to_name[], class_val_to_struct, role_val_to_struct, type_val_to_struct,
+ * user_val_to_struct, and bool_val_to_struct indexes.
+ */
+extern void test_policydb_indexes(policydb_t * p);
+
+/* Test alias datum to ensure that it is as expected
+ *
+ * id = the key for the alias
+ * primary_id = the key for its primary
+ * mode: 0 = test the datum according to the flavor value in the call
+ 1 = automatically detect the flavor value and test the datum accordingly
+ * flavor = flavor value if in mode 0
+ */
+extern void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor);
+
+/* p the policy being inspected
+ * id string role identifier
+ * decl the decl block which we are looking in for the role datum
+ * types the array of string types which we expect the role has in its type ebitmap
+ * len number of elements in types
+ * flags the expected flags in the role typeset (eg., * or ~)
+ *
+ * This is a utility function to test whether the type set associated with a role in a specific
+ * avrule decl block matches our expectations
+ */
+extern role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags);
+
+/* p the policy being inspected
+ * id string attribute identifier
+ * decl the decl block which we are looking in for the attribute datum
+ * types the array of string types which we expect the attribute has in its type ebitmap
+ * len number of elements in types
+ *
+ * This is a utility function to test whether the type set associated with an attribute in a specific
+ * avrule decl block matches our expectations
+ */
+extern void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len);
+
+#endif
diff --git a/libsepol/tests/test-cond.c b/libsepol/tests/test-cond.c
new file mode 100644
index 0000000..32bf6f1
--- /dev/null
+++ b/libsepol/tests/test-cond.c
@@ -0,0 +1,95 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-cond.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+
+static policydb_t basemod;
+static policydb_t base_expanded;
+
+int cond_test_init(void)
+{
+ if (policydb_init(&base_expanded)) {
+ fprintf(stderr, "out of memory!\n");
+ policydb_destroy(&basemod);
+ return -1;
+ }
+
+ if (test_load_policy(&basemod, POLICY_BASE, 1, "test-cond", "refpolicy-base.conf"))
+ goto cleanup;
+
+ if (link_modules(NULL, &basemod, NULL, 0, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ goto cleanup;
+ }
+
+ if (expand_module(NULL, &basemod, &base_expanded, 0, 1)) {
+ fprintf(stderr, "expand module failed\n");
+ goto cleanup;
+ }
+
+ return 0;
+
+ cleanup:
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+ return -1;
+}
+
+int cond_test_cleanup(void)
+{
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+
+ return 0;
+}
+
+static void test_cond_expr_equal(void)
+{
+ cond_node_t *a, *b;
+
+ a = base_expanded.cond_list;
+ while (a) {
+ b = base_expanded.cond_list;
+ while (b) {
+ if (a == b) {
+ CU_ASSERT(cond_expr_equal(a, b));
+ } else {
+ CU_ASSERT(cond_expr_equal(a, b) == 0);
+ }
+ b = b->next;
+ }
+ a = a->next;
+ }
+}
+
+int cond_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "cond_expr_equal", test_cond_expr_equal)) {
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/libsepol/tests/test-cond.h b/libsepol/tests/test-cond.h
new file mode 100644
index 0000000..702d9e0
--- /dev/null
+++ b/libsepol/tests/test-cond.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_COND_H__
+#define __TEST_COND_H__
+
+#include <CUnit/Basic.h>
+
+int cond_test_init(void);
+int cond_test_cleanup(void);
+int cond_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-deps.c b/libsepol/tests/test-deps.c
new file mode 100644
index 0000000..e7d2beb
--- /dev/null
+++ b/libsepol/tests/test-deps.c
@@ -0,0 +1,302 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-deps.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <stdlib.h>
+
+/* Tests for dependency checking / handling, specifically:
+ *
+ * 1 type in module global.
+ * 2 attribute in module global.
+ * 3 object class / perm in module global.
+ * 4 boolean in module global.
+ * 5 role in module global.
+ *
+ * 6 type in module optional.
+ * 7 attribute in module optional.
+ * 8 object class / perm in module optional.
+ * 9 boolean in module optional.
+ * 10 role in module optional.
+ *
+ * 11 type in base optional.
+ * 12 attribute in base optional.
+ * 13 object class / perm in base optional.
+ * 14 boolean in base optional.
+ * 15 role in base optional.
+ *
+ * Each of these tests are done with the dependency met and not
+ * met. Additionally, each of the required symbols is used in the
+ * scope it is required.
+ *
+ * In addition to the simple tests, we have test with more complex
+ * modules that test:
+ *
+ * 17 mutual dependencies between two modules.
+ * 18 circular dependency between three modules.
+ * 19 large number of dependencies in a module with a more complex base.
+ * 20 nested optionals with requires.
+ *
+ * Again, each of these tests is done with the requirements met and not
+ * met.
+ */
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+
+#define BASE_MODREQ_TYPE_GLOBAL 0
+#define BASE_MODREQ_ATTR_GLOBAL 1
+#define BASE_MODREQ_OBJ_GLOBAL 2
+#define BASE_MODREQ_BOOL_GLOBAL 3
+#define BASE_MODREQ_ROLE_GLOBAL 4
+#define BASE_MODREQ_PERM_GLOBAL 5
+#define BASE_MODREQ_TYPE_OPT 6
+#define BASE_MODREQ_ATTR_OPT 7
+#define BASE_MODREQ_OBJ_OPT 8
+#define BASE_MODREQ_BOOL_OPT 9
+#define BASE_MODREQ_ROLE_OPT 10
+#define BASE_MODREQ_PERM_OPT 11
+#define NUM_BASES 12
+
+static policydb_t bases_met[NUM_BASES];
+static policydb_t bases_notmet[NUM_BASES];
+
+extern int mls;
+
+int deps_test_init(void)
+{
+ int i;
+
+ /* To test linking we need 1 base per link test and in
+ * order to load them in the init function we have
+ * to keep them all around. Not ideal, but it shouldn't
+ * matter too much.
+ */
+ for (i = 0; i < NUM_BASES; i++) {
+ if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
+ return -1;
+ }
+
+ for (i = 0; i < NUM_BASES; i++) {
+ if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
+ return -1;
+ }
+
+ return 0;
+}
+
+int deps_test_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_BASES; i++) {
+ policydb_destroy(&bases_met[i]);
+ }
+
+ for (i = 0; i < NUM_BASES; i++) {
+ policydb_destroy(&bases_notmet[i]);
+ }
+
+ return 0;
+}
+
+/* This function performs testing of the dependency handles for module global
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ * req_met boolean indicating whether the base policy meets the
+ * requirements for the modules global block.
+ * b index of the base policy in the global bases_met array.
+ *
+ * policy name of the policy module to load for this test.
+ * decl_type name of the unique type found in the module's global
+ * section is to find that avrule_decl.
+ */
+static void do_deps_modreq_global(int req_met, int b, char *policy, char *decl_type)
+{
+ policydb_t *base;
+ policydb_t mod;
+ policydb_t *mods[] = { &mod };
+ avrule_decl_t *decl;
+ int ret, link_ret;
+ sepol_handle_t *h;
+
+ /* suppress error reporting - this is because we know that we
+ * are going to get errors and don't want libsepol complaining
+ * about it constantly. */
+ h = sepol_handle_create();
+ CU_ASSERT_FATAL(h != NULL);
+ sepol_msg_set_callback(h, NULL, NULL);
+
+ if (req_met) {
+ base = &bases_met[b];
+ link_ret = 0;
+ } else {
+ base = &bases_notmet[b];
+ link_ret = -3;
+ }
+
+ CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+ /* link the modules and check for the correct return value.
+ */
+ ret = link_modules(h, base, mods, 1, 0);
+ CU_ASSERT_FATAL(ret == link_ret);
+ policydb_destroy(&mod);
+
+ if (!req_met)
+ return;
+
+ decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+ CU_ASSERT_FATAL(decl != NULL);
+
+ CU_ASSERT(decl->enabled == 1);
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 1 - 5 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_global(void)
+{
+ /* object classes */
+ do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
+ /* types */
+ do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
+ /* attributes */
+ do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
+ /* booleans */
+ do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
+ /* roles */
+ do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
+ do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+ do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
+}
+
+/* This function performs testing of the dependency handles for module optional
+ * symbols. It is capable of testing 2 scenarios - the dependencies are met
+ * and the dependencies are not met.
+ *
+ * Paramaters:
+ * req_met boolean indicating whether the base policy meets the
+ * requirements for the modules global block.
+ * b index of the base policy in the global bases_met array.
+ *
+ * policy name of the policy module to load for this test.
+ * decl_type name of the unique type found in the module's global
+ * section is to find that avrule_decl.
+ */
+static void do_deps_modreq_opt(int req_met, int ret_val, int b, char *policy, char *decl_type)
+{
+ policydb_t *base;
+ policydb_t mod;
+ policydb_t *mods[] = { &mod };
+ avrule_decl_t *decl;
+ int ret;
+ sepol_handle_t *h;
+
+ /* suppress error reporting - this is because we know that we
+ * are going to get errors and don't want libsepol complaining
+ * about it constantly. */
+ h = sepol_handle_create();
+ CU_ASSERT_FATAL(h != NULL);
+ sepol_msg_set_callback(h, NULL, NULL);
+
+ if (req_met) {
+ base = &bases_met[b];
+ } else {
+ base = &bases_notmet[b];
+ }
+
+ CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
+
+ /* link the modules and check for the correct return value.
+ */
+ ret = link_modules(h, base, mods, 1, 0);
+ CU_ASSERT_FATAL(ret == ret_val);
+ policydb_destroy(&mod);
+ if (ret_val < 0)
+ return;
+
+ decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
+ CU_ASSERT_FATAL(decl != NULL);
+
+ if (req_met) {
+ CU_ASSERT(decl->enabled == 1);
+ } else {
+ CU_ASSERT(decl->enabled == 0);
+ }
+}
+
+/* Test that symbol require statements in the global scope of a module
+ * work correctly. This will cover tests 6 - 10 (described above).
+ *
+ * Each of these policies will require as few symbols as possible to
+ * use the required symbol in addition requiring (for example, the type
+ * test also requires an object class for an allow rule).
+ */
+static void deps_modreq_opt(void)
+{
+ /* object classes */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
+ /* types */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
+ /* attributes */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
+ /* booleans */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
+ /* roles */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
+ /* permissions */
+ do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+ do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
+}
+
+int deps_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
+ return CU_get_error();
+ }
+
+ return 0;
+}
diff --git a/libsepol/tests/test-deps.h b/libsepol/tests/test-deps.h
new file mode 100644
index 0000000..fbd2ace
--- /dev/null
+++ b/libsepol/tests/test-deps.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_DEPS_H__
+#define __TEST_DEPS_H__
+
+#include <CUnit/Basic.h>
+
+int deps_test_init(void);
+int deps_test_cleanup(void);
+int deps_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-downgrade.c b/libsepol/tests/test-downgrade.c
new file mode 100644
index 0000000..1ee7ff4
--- /dev/null
+++ b/libsepol/tests/test-downgrade.c
@@ -0,0 +1,273 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-downgrade.h"
+#include "parse_util.h"
+#include "helpers.h"
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <CUnit/Basic.h>
+
+#define POLICY_BIN_HI "policies/test-downgrade/policy.hi"
+#define POLICY_BIN_LO "policies/test-downgrade/policy.lo"
+
+static policydb_t policydb;
+
+/*
+ * Function Name: downgrade_test_init
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void)
+{
+ /* Initialize the policydb_t structure */
+ if (policydb_init(&policydb)) {
+ fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function Name: downgrade_test_cleanup
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void)
+{
+ policydb_destroy(&policydb);
+
+ return 0;
+}
+
+/*
+ * Function Name: downgrade_add_tests
+ *
+ * Input: CU_pSuite
+ *
+ * Output: Returns 0 upon success. Returns a CUnit error value on failure.
+ *
+ * Description: Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite)
+{
+ if (CU_add_test(suite, "downgrade", test_downgrade) == NULL)
+ return CU_get_error();
+
+ return 0;
+}
+
+/*
+ * Function Name: test_downgrade_possible
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description:
+ * Tests the backward compatability of MLS and Non-MLS binary policy versions.
+ */
+void test_downgrade(void)
+{
+ if (do_downgrade_test(0) < 0)
+ fprintf(stderr,
+ "\nError during downgrade testing of Non-MLS policy\n");
+
+
+ if (do_downgrade_test(1) < 0)
+ fprintf(stderr,
+ "\nError during downgrade testing of MLS policy\n");
+}
+
+/*
+ * Function Name: do_downgrade_test
+ *
+ * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing
+ *
+ * Output: 0 on success, negative number upon failure
+ *
+ * Description: This function handles the downgrade testing.
+ * A binary policy is read into the policydb structure, the
+ * policy version is decreased by a specific amount, written
+ * back out and then read back in again. The process is
+ * repeated until the minimum policy version is reached.
+ */
+int do_downgrade_test(int mls)
+{
+ policydb_t policydb_tmp;
+ int hi, lo, version;
+
+ /* Reset policydb for re-use */
+ policydb_destroy(&policydb);
+ downgrade_test_init();
+
+ /* Read in the hi policy from file */
+ if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) {
+ fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : "");
+ CU_FAIL("Unable to read the binary policy");
+ return -1;
+ }
+
+ /* Change MLS value based on parameter */
+ policydb.mls = mls ? 1 : 0;
+
+ for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) {
+ /* Stash old version number */
+ version = policydb.policyvers;
+
+ /* Try downgrading to each possible version. */
+ for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) {
+
+ /* Reduce policy version */
+ policydb.policyvers = lo;
+
+ /* Write out modified binary policy */
+ if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) {
+ /*
+ * Error from MLS to pre-MLS is expected due
+ * to MLS re-implementation in version 19.
+ */
+ if (mls && lo < POLICYDB_VERSION_MLS)
+ continue;
+
+ fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+ CU_FAIL("Failed to write downgraded binary policy");
+ return -1;
+ }
+
+ /* Make sure we can read back what we wrote. */
+ if (policydb_init(&policydb_tmp)) {
+ fprintf(stderr, "%s: Out of memory!\n",
+ __FUNCTION__);
+ return -1;
+ }
+ if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) {
+ fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
+ CU_FAIL("Unable to read downgraded binary policy");
+ return -1;
+ }
+ policydb_destroy(&policydb_tmp);
+ }
+ /* Restore version number */
+ policydb.policyvers = version;
+ }
+
+ return 0;
+}
+
+/*
+ * Function Name: read_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read binary policy into policydb
+ * structure.
+ */
+int read_binary_policy(const char *path, policydb_t *p)
+{
+ FILE *in_fp = NULL;
+ struct policy_file f;
+ int rc;
+
+ /* Open the binary policy file */
+ if ((in_fp = fopen(path, "rb")) == NULL) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ sepol_handle_destroy(f.handle);
+ return -1;
+ }
+
+ /* Read in the binary policy. */
+ memset(&f, 0, sizeof(struct policy_file));
+ f.type = PF_USE_STDIO;
+ f.fp = in_fp;
+ rc = policydb_read(p, &f, 0);
+
+ sepol_handle_destroy(f.handle);
+ fclose(in_fp);
+ return rc;
+}
+
+/*
+ * Function Name: write_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: open file and write the binary policy from policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *p)
+{
+ FILE *out_fp = NULL;
+ struct policy_file f;
+ sepol_handle_t *handle;
+ int rc;
+
+ /* We don't want libsepol to print warnings to stderr */
+ handle = sepol_handle_create();
+ if (handle == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return -1;
+ }
+ sepol_msg_set_callback(handle, NULL, NULL);
+
+ /* Open the binary policy file for writing */
+ if ((out_fp = fopen(path, "w" )) == NULL) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ sepol_handle_destroy(f.handle);
+ return -1;
+ }
+
+ /* Write the binary policy */
+ memset(&f, 0, sizeof(struct policy_file));
+ f.type = PF_USE_STDIO;
+ f.fp = out_fp;
+ f.handle = handle;
+ rc = policydb_write(p, &f);
+
+ sepol_handle_destroy(f.handle);
+ fclose(out_fp);
+ return rc;
+}
diff --git a/libsepol/tests/test-downgrade.h b/libsepol/tests/test-downgrade.h
new file mode 100644
index 0000000..10a7c3b
--- /dev/null
+++ b/libsepol/tests/test-downgrade.h
@@ -0,0 +1,119 @@
+/*
+ * Author: Mary Garvin <mgarvin@tresys.com>
+ *
+ * Copyright (C) 2007-2008 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_DOWNGRADE_H__
+#define __TEST_DOWNGRADE_H__
+
+#include <CUnit/Basic.h>
+#include <sepol/policydb/policydb.h>
+
+/*
+ * Function Name: downgrade_test_init
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Initialize the policydb (policy data base structure)
+ */
+int downgrade_test_init(void);
+
+/*
+ * Function Name: downgrade_test_cleanup
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Destroys policydb structure
+ */
+int downgrade_test_cleanup(void);
+
+/*
+ * Function Name: downgrade_add_tests
+ *
+ * Input: CU_pSuite
+ *
+ * Output: Returns 0 upon success. Upon failure, a CUnit testing error
+ * value is returned
+ *
+ * Description: Add the given downgrade tests to the downgrade suite.
+ */
+int downgrade_add_tests(CU_pSuite suite);
+
+/*
+ * Function Name: test_downgrade_possible
+ *
+ * Input: None
+ *
+ * Output: None
+ *
+ * Description: Tests the backward compatability of MLS and Non-MLS binary
+ * policy versions.
+ */
+void test_downgrade(void);
+
+/*
+ * Function Name: do_downgrade_test
+ *
+ * Input: int that represents a 0 for Non-MLS policy and a
+ * 1 for MLS policy downgrade testing
+ *
+ * Output: (int) 0 on success, negative number upon failure
+ *
+ * Description: This function handles the downgrade testing. A binary policy
+ * is read into the policydb structure, the policy version is
+ * decreased by a specific amount, written back out and then read
+ * back in again. The process is iterative until the minimum
+ * policy version is reached.
+ */
+int do_downgrade_test(int mls);
+
+/*
+ * Function Name: read_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read in the binary policy
+ * into the policydb structure.
+ */
+int read_binary_policy(const char *path, policydb_t *);
+
+/*
+ * Function Name: write_binary_policy
+ *
+ * Input: char * which is the path to the file containing the binary policy
+ *
+ * Output: Returns 0 upon success. Upon failure, -1 is returned.
+ * Possible failures are, filename with given path does not exist,
+ * a failure to open the file, or a failure from prolicydb_read
+ * function call.
+ *
+ * Description: Get a filename, open file and read in the binary policy
+ * into the policydb structure.
+ */
+int write_binary_policy(const char *path, policydb_t *);
+
+#endif
diff --git a/libsepol/tests/test-expander-attr-map.c b/libsepol/tests/test-expander-attr-map.c
new file mode 100644
index 0000000..5c24ced
--- /dev/null
+++ b/libsepol/tests/test-expander-attr-map.c
@@ -0,0 +1,105 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-attr-map.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t base_expanded2;
+
+void test_expander_attr_mapping(void)
+{
+ /* note that many cases are ommitted because they don't make sense
+ (i.e. declaring in an optional and then using it in the base) or
+ because declare in optional then require in a different optional
+ logic still doesn't work */
+
+ char *typesb1[] = { "attr_check_base_1_1_t", "attr_check_base_1_2_t" };
+ char *typesb2[] = { "attr_check_base_2_1_t", "attr_check_base_2_2_t" };
+ char *typesb3[] = { "attr_check_base_3_1_t", "attr_check_base_3_2_t",
+ "attr_check_base_3_3_t", "attr_check_base_3_4_t"
+ };
+ char *typesb4[] = { "attr_check_base_4_1_t", "attr_check_base_4_2_t" };
+ char *typesb5[] = { "attr_check_base_5_1_t", "attr_check_base_5_2_t" };
+ char *typesb6[] = { "attr_check_base_6_1_t", "attr_check_base_6_2_t",
+ "attr_check_base_6_3_t", "attr_check_base_6_4_t"
+ };
+ char *typesbo2[] = { "attr_check_base_optional_2_1_t",
+ "attr_check_base_optional_2_2_t"
+ };
+ char *typesbo5[] = { "attr_check_base_optional_5_1_t",
+ "attr_check_base_optional_5_2_t"
+ };
+ char *typesm2[] = { "attr_check_mod_2_1_t", "attr_check_mod_2_2_t" };
+ char *typesm4[] = { "attr_check_mod_4_1_t", "attr_check_mod_4_2_t" };
+ char *typesm5[] = { "attr_check_mod_5_1_t", "attr_check_mod_5_2_t" };
+ char *typesm6[] = { "attr_check_mod_6_1_t", "attr_check_mod_6_2_t",
+ "attr_check_mod_6_3_t", "attr_check_mod_6_4_t"
+ };
+ char *typesmo2[] = { "attr_check_mod_optional_4_1_t",
+ "attr_check_mod_optional_4_2_t"
+ };
+ char *typesb10[] = { "attr_check_base_10_1_t", "attr_check_base_10_2_t" };
+ char *typesb11[] = { "attr_check_base_11_3_t", "attr_check_base_11_4_t" };
+ char *typesm10[] = { "attr_check_mod_10_1_t", "attr_check_mod_10_2_t" };
+ char *typesm11[] = { "attr_check_mod_11_3_t", "attr_check_mod_11_4_t" };
+
+ test_attr_types(&base_expanded2, "attr_check_base_1", NULL, typesb1, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_2", NULL, typesb2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_3", NULL, typesb3, 4);
+ test_attr_types(&base_expanded2, "attr_check_base_4", NULL, typesb4, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_5", NULL, typesb5, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_6", NULL, typesb6, 4);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_2", NULL, typesbo2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_5", NULL, typesbo5, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_2", NULL, typesm2, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_4", NULL, typesm4, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_5", NULL, typesm5, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_6", NULL, typesm6, 4);
+ test_attr_types(&base_expanded2, "attr_check_mod_optional_4", NULL, typesmo2, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_7", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_9", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_base_10", NULL, typesb10, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_11", NULL, typesb11, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_7", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_9", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_10", NULL, typesm10, 2);
+ test_attr_types(&base_expanded2, "attr_check_mod_11", NULL, typesm11, 2);
+ test_attr_types(&base_expanded2, "attr_check_base_optional_8", NULL, NULL, 0);
+ test_attr_types(&base_expanded2, "attr_check_mod_optional_7", NULL, NULL, 0);
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_2_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_1_t"));
+ CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_2_t"));
+}
diff --git a/libsepol/tests/test-expander-attr-map.h b/libsepol/tests/test-expander-attr-map.h
new file mode 100644
index 0000000..6a10089
--- /dev/null
+++ b/libsepol/tests/test-expander-attr-map.h
@@ -0,0 +1,26 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER__ATTR_MAP_H__
+#define __TEST_EXPANDER__ATTR_MAP_H__
+
+void test_expander_attr_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander-roles.c b/libsepol/tests/test-expander-roles.c
new file mode 100644
index 0000000..ecfa88e
--- /dev/null
+++ b/libsepol/tests/test-expander-roles.c
@@ -0,0 +1,37 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-roles.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t role_expanded;
+
+void test_expander_role_mapping(void)
+{
+ char *types1[] = { "role_check_1_1_t", "role_check_1_2_t" };
+
+ test_role_type_set(&role_expanded, "role_check_1", NULL, types1, 2, 0);
+}
diff --git a/libsepol/tests/test-expander-roles.h b/libsepol/tests/test-expander-roles.h
new file mode 100644
index 0000000..380d2ef
--- /dev/null
+++ b/libsepol/tests/test-expander-roles.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_ROLE_H__
+#define __TEST_EXPANDER_ROLE_H__
+
+void test_expander_role_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander-users.c b/libsepol/tests/test-expander-users.c
new file mode 100644
index 0000000..549492b
--- /dev/null
+++ b/libsepol/tests/test-expander-users.c
@@ -0,0 +1,75 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ * Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-expander-users.h"
+
+#include <sepol/policydb/policydb.h>
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+extern policydb_t user_expanded;
+
+static void check_user_roles(policydb_t * p, char *user_name, char **role_names, int num_roles)
+{
+ user_datum_t *user;
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ int j;
+ unsigned char *found; /* array of booleans of roles found */
+ int extra = 0; /* number of extra roles found */
+
+ user = (user_datum_t *) hashtab_search(p->p_users.table, user_name);
+ if (!user) {
+ printf("%s not found\n", user_name);
+ CU_FAIL("user not found");
+ return;
+ }
+ found = calloc(num_roles, sizeof(unsigned char));
+ CU_ASSERT_FATAL(found != NULL);
+ ebitmap_for_each_bit(&user->roles.roles, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ extra++;
+ for (j = 0; j < num_roles; j++) {
+ if (strcmp(role_names[j], p->p_role_val_to_name[i]) == 0) {
+ extra--;
+ found[j] += 1;
+ break;
+ }
+ }
+ }
+ }
+ for (j = 0; j < num_roles; j++) {
+ if (found[j] != 1) {
+ printf("role %s associated with user %s %d times\n", role_names[j], user_name, found[j]);
+ CU_FAIL("user mapping failure\n");
+ }
+ }
+ free(found);
+ CU_ASSERT_EQUAL(extra, 0);
+}
+
+void test_expander_user_mapping(void)
+{
+ char *roles1[] = { "user_check_1_1_r", "user_check_1_2_r" };
+
+ check_user_roles(&user_expanded, "user_check_1", roles1, 2);
+}
diff --git a/libsepol/tests/test-expander-users.h b/libsepol/tests/test-expander-users.h
new file mode 100644
index 0000000..cb12143
--- /dev/null
+++ b/libsepol/tests/test-expander-users.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Author: Chris PeBenito <cpebenito@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_USER_H__
+#define __TEST_EXPANDER_USER_H__
+
+void test_expander_user_mapping(void);
+
+#endif
diff --git a/libsepol/tests/test-expander.c b/libsepol/tests/test-expander.c
new file mode 100644
index 0000000..ded1d9d
--- /dev/null
+++ b/libsepol/tests/test-expander.c
@@ -0,0 +1,218 @@
+/*
+ * Authors: Chad Sellers <csellers@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This is where the expander tests should go, including:
+ * - check role, type, bool, user mapping
+ * - add symbols declared in enabled optionals
+ * - do not add symbols declared in disabled optionals
+ * - add rules from enabled optionals
+ * - do not add rules from disabled optionals
+ * - verify attribute mapping
+
+ * - check conditional expressions for correct mapping
+ */
+
+#include "test-expander.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-expander-users.h"
+#include "test-expander-roles.h"
+#include "test-expander-attr-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <limits.h>
+#include <stdlib.h>
+
+policydb_t role_expanded;
+policydb_t user_expanded;
+policydb_t base_expanded2;
+static policydb_t basemod;
+static policydb_t basemod2;
+static policydb_t mod2;
+static policydb_t base_expanded;
+static policydb_t base_only_mod;
+static policydb_t base_only_expanded;
+static policydb_t role_basemod;
+static policydb_t role_mod;
+static policydb_t user_basemod;
+static policydb_t user_mod;
+static policydb_t alias_basemod;
+static policydb_t alias_mod;
+static policydb_t alias_expanded;
+static uint32_t *typemap;
+extern int mls;
+
+/* Takes base, some number of modules, links them, and expands them
+ reads source from myfiles array, which has the base string followed by
+ each module string */
+int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, char **myfiles)
+{
+ char *filename[num_modules + 1];
+ int i;
+
+ for (i = 0; i < num_modules + 1; i++) {
+ filename[i] = calloc(PATH_MAX, sizeof(char));
+ if (snprintf(filename[i], PATH_MAX, "policies/test-expander/%s%s", myfiles[i], mls ? ".mls" : ".std") < 0)
+ return -1;
+ }
+
+ if (policydb_init(mybase)) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ for (i = 0; i < num_modules; i++) {
+ if (policydb_init(mymodules[i])) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+ }
+
+ if (policydb_init(myexpanded)) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ mybase->policy_type = POLICY_BASE;
+ mybase->mls = mls;
+
+ if (read_source_policy(mybase, filename[0], myfiles[0])) {
+ fprintf(stderr, "read source policy failed %s\n", filename[0]);
+ return -1;
+ }
+
+ for (i = 1; i < num_modules + 1; i++) {
+ mymodules[i - 1]->policy_type = POLICY_MOD;
+ mymodules[i - 1]->mls = mls;
+ if (read_source_policy(mymodules[i - 1], filename[i], myfiles[i])) {
+ fprintf(stderr, "read source policy failed %s\n", filename[i]);
+ return -1;
+ }
+ }
+
+ if (link_modules(NULL, mybase, mymodules, num_modules, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ if (expand_module(NULL, mybase, myexpanded, 0, 0)) {
+ fprintf(stderr, "expand modules failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int expander_test_init(void)
+{
+ char *small_base_file = "small-base.conf";
+ char *base_only_file = "base-base-only.conf";
+ int rc;
+ policydb_t *mymod2;
+ char *files2[] = { "small-base.conf", "module.conf" };
+ char *role_files[] = { "role-base.conf", "role-module.conf" };
+ char *user_files[] = { "user-base.conf", "user-module.conf" };
+ char *alias_files[] = { "alias-base.conf", "alias-module.conf" };
+
+ rc = expander_policy_init(&basemod, 0, NULL, &base_expanded, &small_base_file);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &mod2;
+ rc = expander_policy_init(&basemod2, 1, &mymod2, &base_expanded2, files2);
+ if (rc != 0)
+ return rc;
+
+ rc = expander_policy_init(&base_only_mod, 0, NULL, &base_only_expanded, &base_only_file);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &role_mod;
+ rc = expander_policy_init(&role_basemod, 1, &mymod2, &role_expanded, role_files);
+ if (rc != 0)
+ return rc;
+
+ /* Just init the base for now, until we figure out how to separate out
+ mls and non-mls tests since users can't be used in mls module */
+ mymod2 = &user_mod;
+ rc = expander_policy_init(&user_basemod, 0, NULL, &user_expanded, user_files);
+ if (rc != 0)
+ return rc;
+
+ mymod2 = &alias_mod;
+ rc = expander_policy_init(&alias_basemod, 1, &mymod2, &alias_expanded, alias_files);
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
+int expander_test_cleanup(void)
+{
+ policydb_destroy(&basemod);
+ policydb_destroy(&base_expanded);
+ free(typemap);
+
+ return 0;
+}
+
+static void test_expander_indexes(void)
+{
+ test_policydb_indexes(&base_expanded);
+}
+
+static void test_expander_alias(void)
+{
+ test_alias_datum(&alias_expanded, "alias_check_1_a", "alias_check_1_t", 1, 0);
+ test_alias_datum(&alias_expanded, "alias_check_2_a", "alias_check_2_t", 1, 0);
+ test_alias_datum(&alias_expanded, "alias_check_3_a", "alias_check_3_t", 1, 0);
+}
+
+int expander_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "expander_indexes", test_expander_indexes)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "expander_attr_mapping", test_expander_attr_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ if (NULL == CU_add_test(suite, "expander_role_mapping", test_expander_role_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "expander_user_mapping", test_expander_user_mapping)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "expander_alias", test_expander_alias)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/libsepol/tests/test-expander.h b/libsepol/tests/test-expander.h
new file mode 100644
index 0000000..5964133
--- /dev/null
+++ b/libsepol/tests/test-expander.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_EXPANDER_H__
+#define __TEST_EXPANDER_H__
+
+#include <CUnit/Basic.h>
+
+int expander_test_init(void);
+int expander_test_cleanup(void);
+int expander_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/tests/test-linker-cond-map.c b/libsepol/tests/test-linker-cond-map.c
new file mode 100644
index 0000000..0ef0d69
--- /dev/null
+++ b/libsepol/tests/test-linker-cond-map.c
@@ -0,0 +1,159 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for conditionals
+ * Test each cond/bool for these
+ * - boolean copied correctly (state is correct)
+ * - conditional expression is correct
+ * Tests:
+ * - single boolean in base
+ * - single boolean in module
+ * - single boolean in base optional
+ * - single boolean in module optional
+ * - 2 booleans in base
+ * - 2 booleans in module
+ * - 2 booleans in base optional
+ * - 2 booleans in module optional
+ * - 2 booleans, base and module
+ * - 2 booleans, base optional and module
+ * - 2 booleans, base optional and module optional
+ * - 3 booleans, base, base optional, module
+ * - 4 boolean, base, base optional, module, module optional
+ */
+
+typedef struct test_cond_expr {
+ char *bool;
+ uint32_t expr_type;
+} test_cond_expr_t;
+
+void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len)
+{
+ int i;
+ cond_expr_t *expr;
+
+ CU_ASSERT_FATAL(d->cond_list != NULL);
+ CU_ASSERT_FATAL(d->cond_list->expr != NULL);
+
+ expr = d->cond_list->expr;
+
+ for (i = 0; i < len; i++) {
+ CU_ASSERT_FATAL(expr != NULL);
+
+ CU_ASSERT(expr->expr_type == bools[i].expr_type);
+ if (bools[i].bool) {
+ CU_ASSERT(strcmp(p->sym_val_to_name[SYM_BOOLS][expr->bool - 1], bools[i].bool) == 0);
+ }
+ expr = expr->next;
+ }
+}
+
+void test_bool_state(policydb_t * p, char *bool, int state)
+{
+ cond_bool_datum_t *b;
+
+ b = hashtab_search(p->p_bools.table, bool);
+ CU_ASSERT_FATAL(b != NULL);
+ CU_ASSERT(b->state == state);
+}
+
+void base_cond_tests(policydb_t * base)
+{
+ avrule_decl_t *d;
+ unsigned int decls[1];
+ test_cond_expr_t bools[2];
+
+ /* these tests look at booleans and conditionals in the base only
+ * to ensure that they aren't altered or removed during the link process */
+
+ /* bool existance and state, global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_b_bool_1", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_b_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, optional scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o1_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "o1_b_bool_1", 1);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "o1_b_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+}
+
+void module_cond_tests(policydb_t * base)
+{
+ avrule_decl_t *d;
+ unsigned int decls[1];
+ test_cond_expr_t bools[3];
+
+ /* bool existance and state, module 1 global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_m1_bool_1", 1);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_m1_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, module 1 optional scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o1_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "o1_m1_bool_1", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "o1_m1_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ test_cond_expr_mapping(base, d, bools, 1);
+
+ /* bool existance and state, module 2 global scope */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "g_m2_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_sym_presence(base, "g_m2_bool_2", SYM_BOOLS, SCOPE_DECL, decls, 1);
+ test_bool_state(base, "g_m2_bool_1", 1);
+ test_bool_state(base, "g_m2_bool_2", 0);
+ /* conditional expression mapped correctly */
+ bools[0].bool = "g_m2_bool_1";
+ bools[0].expr_type = COND_BOOL;
+ bools[1].bool = "g_m2_bool_2";
+ bools[1].expr_type = COND_BOOL;
+ bools[2].bool = NULL;
+ bools[2].expr_type = COND_AND;
+ test_cond_expr_mapping(base, d, bools, 3);
+}
diff --git a/libsepol/tests/test-linker-cond-map.h b/libsepol/tests/test-linker-cond-map.h
new file mode 100644
index 0000000..148c6f6
--- /dev/null
+++ b/libsepol/tests/test-linker-cond-map.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_COND_MAP_H__
+#define __TEST_LINKER_COND_MAP_H__
+
+extern void base_cond_tests(policydb_t * base);
+extern void module_cond_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker-roles.c b/libsepol/tests/test-linker-roles.c
new file mode 100644
index 0000000..2c4a804
--- /dev/null
+++ b/libsepol/tests/test-linker-roles.c
@@ -0,0 +1,206 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for roles:
+ * Test for each of these for
+ * - role in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type_set
+ * - scope datum has correct decl ids
+ * - dominates bitmap is correct
+ * Tests:
+ * - role in base, no modules
+ * - role in base optional, no modules
+ * - role a in base, b in module
+ * - role a in base and module (additive)
+ * - role a in base and 2 module
+ * - role a in base optional, b in module
+ * - role a in base, b in module optional
+ * - role a in base optional, b in module optional
+ * - role a in base optional and module
+ * - role a in base and module optional
+ * - role a in base optional and module optional
+ * - role a in base optional and 2 modules
+ * - role a and b in base, b dom a, are types correct (TODO)
+ */
+
+/* this simply tests whether the passed in role only has its own
+ * value in its dominates ebitmap */
+static void only_dominates_self(policydb_t * p, role_datum_t * role)
+{
+ ebitmap_node_t *tnode;
+ unsigned int i;
+ int found = 0;
+
+ ebitmap_for_each_bit(&role->dominates, tnode, i) {
+ if (ebitmap_node_get_bit(tnode, i)) {
+ found++;
+ CU_ASSERT(i == role->s.value - 1);
+ }
+ }
+ CU_ASSERT(found == 1);
+}
+
+void base_role_tests(policydb_t * base)
+{
+ avrule_decl_t *decl;
+ role_datum_t *role;
+ unsigned int decls[2];
+ char *types[2];
+
+ /* These tests look at roles in the base only, the desire is to ensure that
+ * roles are not destroyed or otherwise removed during the link process */
+
+ /**** test for g_b_role_1 in base and decl 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (g_b_type_1, no negset, no flags) */
+ types[0] = "g_b_type_1";
+ role = test_role_type_set(base, "g_b_role_1", NULL, types, 1, 0);
+ /* This role should only dominate itself */
+ only_dominates_self(base, role);
+
+ /**** test for o1_b_role_1 in optional (decl 2) ****/
+ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ decls[0] = decl->decl_id;
+ test_sym_presence(base, "o1_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (o1_b_type_1, no negset, no flags) */
+ types[0] = "o1_b_type_1";
+ role = test_role_type_set(base, "o1_b_role_1", decl, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+}
+
+void module_role_tests(policydb_t * base)
+{
+ role_datum_t *role;
+ avrule_decl_t *decl;
+ unsigned int decls[3];
+ char *types[3];
+
+ /* These tests are run when the base is linked with 2 modules,
+ * They should test whether the roles get copied correctly from the
+ * modules into the base */
+
+ /**** test for role in module 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "g_m1_role_1", NULL, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in module 1 (optional) ****/
+ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ decls[0] = decl->decl_id;
+ test_sym_presence(base, "o1_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1);
+ /* make sure it has the correct type set (o1_m1_type_1, no negset, no flags) */
+ types[0] = "o1_m1_type_1";
+ role = test_role_type_set(base, "o1_m1_role_1", decl, types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /* These test whether the type sets are copied to the right place and
+ * correctly unioned when they should be */
+
+ /**** test for type added to base role in module 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */
+ types[0] = "g_b_type_2"; /* added in base when declared */
+ types[1] = "g_m1_type_1"; /* added in module */
+ role = test_role_type_set(base, "g_b_role_2", NULL, types, 2, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for type added to base role in module 1 & 2 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+ test_sym_presence(base, "g_b_role_3", SYM_ROLES, SCOPE_DECL, decls, 3);
+ /* make sure it has the correct type set (g_b_type_2, g_m1_type_2, g_m2_type_2, no negset, no flags) */
+ types[0] = "g_b_type_2"; /* added in base when declared */
+ types[1] = "g_m1_type_2"; /* added in module 1 */
+ types[2] = "g_m2_type_2"; /* added in module 2 */
+ role = test_role_type_set(base, "g_b_role_3", NULL, types, 3, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base optional and module 1 (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "o1_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "o1_b_role_2", NULL, types, 1, 0);
+ types[0] = "o1_b_type_1";
+ role = test_role_type_set(base, "o1_b_role_2", test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"))->decl_id;
+ test_sym_presence(base, "g_b_role_4", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */
+ types[0] = "g_b_type_2";
+ role = test_role_type_set(base, "g_b_role_4", NULL, types, 1, 0);
+ types[0] = "g_m1_type_2";
+ role = test_role_type_set(base, "g_b_role_4", test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+ test_sym_presence(base, "o3_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 2);
+ /* this one will have 2 type sets, one in the 3rd base optional and one in the 3rd module optional */
+ types[0] = "o3_b_type_1";
+ role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"), types, 1, 0);
+ types[0] = "o3_m1_type_1";
+ role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"), types, 1, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+
+ /**** test for role in base and module 1 optional (additive) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+ decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id;
+ test_sym_presence(base, "o4_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 3);
+ /* this one will have 2 type sets, one in the global symtab (with both module types) and one in the 4th optional of base */
+ types[0] = "g_m1_type_1";
+ role = test_role_type_set(base, "o4_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"), types, 1, 0);
+ types[0] = "g_m2_type_1";
+ types[1] = "g_m1_type_2";
+ role = test_role_type_set(base, "o4_b_role_1", NULL, types, 2, 0);
+ /* and only dominates itself */
+ only_dominates_self(base, role);
+}
diff --git a/libsepol/tests/test-linker-roles.h b/libsepol/tests/test-linker-roles.h
new file mode 100644
index 0000000..f7407df
--- /dev/null
+++ b/libsepol/tests/test-linker-roles.h
@@ -0,0 +1,29 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_ROLES_H__
+#define __TEST_LINKER_ROLES_H__
+
+#include <sepol/policydb/policydb.h>
+
+extern void base_role_tests(policydb_t * base);
+extern void module_role_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker-types.c b/libsepol/tests/test-linker-types.c
new file mode 100644
index 0000000..94f16ac
--- /dev/null
+++ b/libsepol/tests/test-linker-types.c
@@ -0,0 +1,317 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ * Chad Sellers <csellers@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+
+#include <CUnit/Basic.h>
+#include <stdlib.h>
+
+/* Tests for types:
+ * Test for each of these for
+ * - type in appropriate symtab (global and decl)
+ * - datum in the decl symtab has correct type bitmap (if attr)
+ * - primary is set correctly
+ * - scope datum has correct decl ids
+ * Tests:
+ * - type in base, no modules
+ * - type in base optional, no modules
+ * - type a in base, b in module
+ * - type a in base optional, b in module
+ * - type a in base, b in module optional
+ * - type a in base optional, b in module optional
+ * - attr in base, no modules
+ * - attr in base optional, no modules
+ * - attr a in base, b in module
+ * - attr a in base optional, b in module
+ * - attr a in base, b in module optional
+ * - attr a in base optional, b in module optional
+ * - attr a declared in base, added to in module
+ * - attr a declared in base, added to in module optional
+ * - attr a declared in base, added to in 2 modules
+ * - attr a declared in base, added to in 2 modules (optional and global)
+ * - attr a declared in base optional, added to in module
+ * - attr a declared in base optional, added to in module optional
+ * - attr a added to in base optional, declared in module
+ * - attr a added to in base optional, declared in module optional
+ * - attr a added to in base optional, declared in module, added to in other module
+ * - attr a added to in base optional, declared in module optional, added to in other module
+ * - attr a added to in base optional, declared in module , added to in other module optional
+ * - attr a added to in base optional, declared in module optional, added to in other module optional
+ * - alias in base of primary type in base, no modules
+ * - alias in base optional of primary type in base, no modules
+ * - alias in base optional of primary type in base optional
+ * - alias in module of primary type in base
+ * - alias in module optional of primary type in base
+ * - alias in module optional of primary type in base optional
+ * - alias in module of primary type in module
+ * - alias in module optional of primary type in module
+ * - alias in module optional of primary type in module optional
+ * - alias a in base, b in module, primary type in base
+ * - alias a in base, b in module, primary type in module
+ * - alias a in base optional, b in module, primary type in base
+ * - alias a in base optional, b in module, primary type in module
+ * - alias a in base, b in module optional, primary type in base
+ * - alias a in base, b in module optional, primary type in module
+ * - alias a in base optional, b in module optional, primary type in base
+ * - alias a in base optional, b in module optional, primary type in module
+ * - alias a in base, required in module, primary type in base
+ * - alias a in base, required in base optional, primary type in base
+ * - alias a in base, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in base
+ * - alias a in module, required in module optional, primary type in base
+ * - alias a in base optional, required in module, primary type in base
+ * - alias a in base optional, required in different base optional, primary type in base
+ * - alias a in base optional, required in module optional, primary type in base
+ * - alias a in module optional, required in base optional, primary type in base
+ * - alias a in module optional, required in module optional, primary type in base
+ * - alias a in module, required in base optional, primary type in module
+ * - alias a in module, required in module optional, primary type in module
+ * - alias a in base optional, required in module, primary type in module
+ * - alias a in base optional, required in different base optional, primary type in module
+ * - alias a in base optional, required in module optional, primary type in module
+ * - alias a in module optional, required in base optional, primary type in module
+ * - alias a in module optional, required in module optional, primary type in module
+ */
+
+/* Don't pass in decls from global blocks since symbols aren't stored in their symtab */
+static void test_type_datum(policydb_t * p, char *id, unsigned int *decls, int len, unsigned int primary)
+{
+ int i;
+ unsigned int value;
+ type_datum_t *type;
+
+ /* just test the type datums for each decl to see if it is what we expect */
+ type = hashtab_search(p->p_types.table, id);
+
+ CU_ASSERT_FATAL(type != NULL);
+ CU_ASSERT(type->primary == primary);
+ CU_ASSERT(type->flavor == TYPE_TYPE);
+
+ value = type->s.value;
+
+ for (i = 0; i < len; i++) {
+ type = hashtab_search(p->decl_val_to_struct[decls[i] - 1]->p_types.table, id);
+ CU_ASSERT_FATAL(type != NULL);
+ CU_ASSERT(type->primary == primary);
+ CU_ASSERT(type->flavor == TYPE_TYPE);
+ CU_ASSERT(type->s.value == value);
+ }
+
+}
+
+void base_type_tests(policydb_t * base)
+{
+ unsigned int decls[2];
+ char *types[2];
+
+ /* These tests look at types in the base only, the desire is to ensure that
+ * types are not destroyed or otherwise removed during the link process.
+ * if this happens these tests won't work anyway since we are using types to
+ * mark blocks */
+
+ /**** test for g_b_type_1 in base and decl 1 (global) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "g_b_type_1", NULL, 0, 1);
+ /* this attr is in the same decl as the type */
+ test_sym_presence(base, "g_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_b_type_1";
+ test_attr_types(base, "g_b_attr_1", NULL, types, 1);
+
+ /**** test for o1_b_type_1 in optional (decl 2) ****/
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ test_sym_presence(base, "o1_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "o1_b_type_1", NULL, 0, 1);
+ /* this attr is in the same decl as the type */
+ test_sym_presence(base, "o1_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o1_b_type_1";
+ test_attr_types(base, "o1_b_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* tests for aliases */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_b_alias_1", "g_b_type_3", 1, 0);
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o6_b"))->decl_id;
+ test_sym_presence(base, "g_b_alias_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_b_alias_2", "g_b_type_3", 1, 0);
+
+}
+
+void module_type_tests(policydb_t * base)
+{
+ unsigned int decls[2];
+ char *types[2];
+ avrule_decl_t *d;
+
+ /* These tests look at types that were copied from modules or attributes
+ * that were modified and declared in modules and base. These apply to
+ * declarations and modifications in and out of optionals. These tests
+ * should ensure that types and attributes are correctly copied from modules
+ * and that attribute type sets are correctly copied and mapped. */
+
+ /* note: scope for attributes is currently smashed if the attribute is declared
+ * somewhere so the scope test only looks at global, the type bitmap test looks
+ * at the appropriate decl symtab */
+
+ /* test for type in module 1 (global) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "g_m1_type_1", NULL, 0, 1);
+ /* attr has is in the same decl as the above type */
+ test_sym_presence(base, "g_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_1";
+ types[1] = "g_m1_type_2";
+ test_attr_types(base, "g_m1_attr_1", NULL, types, 2);
+
+ /* test for type in module 1 (optional) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+ test_sym_presence(base, "o1_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_type_datum(base, "o1_m1_type_1", NULL, 0, 1);
+ /* attr has is in the same decl as the above type */
+ test_sym_presence(base, "o1_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o1_m1_type_2";
+ test_attr_types(base, "o1_m1_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* test for attr declared in base, added to in module (global).
+ * Since these are both global it'll be merged in the main symtab */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_3";
+ test_attr_types(base, "g_b_attr_3", NULL, types, 1);
+
+ /* test for attr declared in base, added to in module (optional). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id;
+ types[0] = "o1_m1_type_3";
+ test_attr_types(base, "g_b_attr_4", base->decl_val_to_struct[decls[0] - 1], types, 1);
+
+ /* test for attr declared in base, added to in 2 modules (global). (merged in main symtab) */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_5", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_4";
+ types[1] = "g_m2_type_4";
+ test_attr_types(base, "g_b_attr_5", NULL, types, 2);
+
+ /* test for attr declared in base, added to in 2 modules (optional/global). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id;
+ test_sym_presence(base, "g_b_attr_6", SYM_TYPES, SCOPE_DECL, decls, 1);
+ /* module 2 was global to its type is in main symtab */
+ types[0] = "g_m2_type_5";
+ test_attr_types(base, "g_b_attr_6", NULL, types, 1);
+ d = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"));
+ types[0] = "o3_m1_type_2";
+ test_attr_types(base, "g_b_attr_6", d, types, 1);
+
+ /* test for attr declared in base optional, added to in module (global). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id;
+ test_sym_presence(base, "o4_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_5";
+ test_attr_types(base, "o4_b_attr_1", NULL, types, 1);
+
+ /* test for attr declared in base optional, added to in module (optional). */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id;
+ test_sym_presence(base, "o1_b_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1");
+ types[0] = "o1_m1_type_5";
+ test_attr_types(base, "o1_b_attr_2", d, types, 1);
+
+ /* test for attr declared in module, added to in base optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b");
+ types[0] = "o1_b_type_2";
+ test_attr_types(base, "g_m1_attr_2", d, types, 1);
+
+ /* test for attr declared in module optional, added to in base optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id;
+ test_sym_presence(base, "o3_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+ types[0] = "o4_b_type_1";
+ test_attr_types(base, "o3_m1_attr_1", d, types, 1);
+
+ /* attr a added to in base optional, declared/added to in module, added to in other module */
+ /* first the module declare/add and module 2 add (since its global it'll be in the main symtab */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_6";
+ types[1] = "g_m2_type_3";
+ test_attr_types(base, "g_m1_attr_3", NULL, types, 2);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b");
+ types[0] = "o4_b_type_2";
+ test_attr_types(base, "g_m1_attr_3", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module optional, added to in other module */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o3_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o3_m1_type_3";
+ test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+ /* module 2's type will be in the main symtab */
+ types[0] = "g_m2_type_6";
+ test_attr_types(base, "o3_m1_attr_2", NULL, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_b");
+ types[0] = "o2_b_type_1";
+ test_attr_types(base, "o3_m1_attr_2", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module , added to in other module optional */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m1_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "g_m1_type_7";
+ test_attr_types(base, "g_m1_attr_4", NULL, types, 1);
+ /* module 2 */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+ types[0] = "o2_m2_type_1";
+ test_attr_types(base, "g_m1_attr_4", d, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+ types[0] = "o5_b_type_1";
+ test_attr_types(base, "g_m1_attr_4", d, types, 1);
+
+ /* attr a added to in base optional, declared/added in module optional, added to in other module optional */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_m1");
+ decls[0] = d->decl_id;
+ test_sym_presence(base, "o4_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ types[0] = "o4_m1_type_1";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+ /* module 2 */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2");
+ types[0] = "o2_m2_type_2";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+ /* base add */
+ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b");
+ types[0] = "o5_b_type_2";
+ test_attr_types(base, "o4_m1_attr_1", d, types, 1);
+
+ /* tests for aliases */
+ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id;
+ test_sym_presence(base, "g_m_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1);
+ test_alias_datum(base, "g_m_alias_1", "g_b_type_3", 1, 0);
+
+}
diff --git a/libsepol/tests/test-linker-types.h b/libsepol/tests/test-linker-types.h
new file mode 100644
index 0000000..0c860eb
--- /dev/null
+++ b/libsepol/tests/test-linker-types.h
@@ -0,0 +1,27 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_TYPES_H__
+#define __TEST_LINKER_TYPES_H__
+
+extern void base_type_tests(policydb_t * base);
+extern void module_type_tests(policydb_t * base);
+
+#endif
diff --git a/libsepol/tests/test-linker.c b/libsepol/tests/test-linker.c
new file mode 100644
index 0000000..d08f219
--- /dev/null
+++ b/libsepol/tests/test-linker.c
@@ -0,0 +1,154 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This is where the linker tests should go, including:
+ * - check role, type, bool, user, attr mapping
+ * - check for properly enabled optional
+ * - check for properly disabled optional
+ * - check for non-optional disabled blocks
+ * - properly add symbols declared in optionals
+ */
+
+#include "test-linker.h"
+#include "parse_util.h"
+#include "helpers.h"
+#include "test-common.h"
+#include "test-linker-roles.h"
+#include "test-linker-types.h"
+#include "test-linker-cond-map.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/link.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/expand.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define NUM_MODS 2
+#define NUM_POLICIES NUM_MODS+1
+
+#define BASEMOD NUM_MODS
+const char *policies[NUM_POLICIES] = {
+ "module1.conf",
+ "module2.conf",
+ "small-base.conf",
+};
+
+static policydb_t basenomods;
+static policydb_t linkedbase;
+static policydb_t *modules[NUM_MODS];
+extern int mls;
+
+int linker_test_init(void)
+{
+ int i;
+
+ if (test_load_policy(&linkedbase, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+ return -1;
+
+ if (test_load_policy(&basenomods, POLICY_BASE, mls, "test-linker", policies[BASEMOD]))
+ return -1;
+
+ for (i = 0; i < NUM_MODS; i++) {
+
+ modules[i] = calloc(1, sizeof(*modules[i]));
+ if (!modules[i]) {
+ fprintf(stderr, "out of memory!\n");
+ return -1;
+ }
+
+ if (test_load_policy(modules[i], POLICY_MOD, mls, "test-linker", policies[i]))
+ return -1;
+
+ }
+
+ if (link_modules(NULL, &linkedbase, modules, NUM_MODS, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ if (link_modules(NULL, &basenomods, NULL, 0, 0)) {
+ fprintf(stderr, "link modules failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int linker_test_cleanup(void)
+{
+ int i;
+
+ policydb_destroy(&basenomods);
+ policydb_destroy(&linkedbase);
+
+ for (i = 0; i < NUM_MODS; i++) {
+ policydb_destroy(modules[i]);
+ free(modules[i]);
+ }
+ return 0;
+}
+
+static void test_linker_indexes(void)
+{
+ test_policydb_indexes(&linkedbase);
+}
+
+static void test_linker_roles(void)
+{
+ base_role_tests(&basenomods);
+ base_role_tests(&linkedbase);
+ module_role_tests(&linkedbase);
+}
+
+static void test_linker_types(void)
+{
+ base_type_tests(&basenomods);
+ base_type_tests(&linkedbase);
+ module_type_tests(&linkedbase);
+}
+
+static void test_linker_cond(void)
+{
+ base_cond_tests(&basenomods);
+ base_cond_tests(&linkedbase);
+ module_cond_tests(&linkedbase);
+}
+
+int linker_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "linker_indexes", test_linker_indexes)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_types", test_linker_types)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_roles", test_linker_roles)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ if (NULL == CU_add_test(suite, "linker_cond", test_linker_cond)) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+ return 0;
+}
diff --git a/libsepol/tests/test-linker.h b/libsepol/tests/test-linker.h
new file mode 100644
index 0000000..16339a0
--- /dev/null
+++ b/libsepol/tests/test-linker.h
@@ -0,0 +1,30 @@
+/*
+ * Author: Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2006 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEST_LINKER_H__
+#define __TEST_LINKER_H__
+
+#include <CUnit/Basic.h>
+
+int linker_test_init(void);
+int linker_test_cleanup(void);
+int linker_add_tests(CU_pSuite suite);
+
+#endif
diff --git a/libsepol/utils/Makefile b/libsepol/utils/Makefile
new file mode 100644
index 0000000..6864114
--- /dev/null
+++ b/libsepol/utils/Makefile
@@ -0,0 +1,24 @@
+# Installation directories.
+PREFIX ?= $(DESTDIR)/usr
+BINDIR ?= $(PREFIX)/bin
+
+CFLAGS ?= -Wall -Werror
+override CFLAGS += -I../include
+LDLIBS += -L../src -lsepol
+
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+
+all: $(TARGETS)
+
+install: all
+ -mkdir -p $(BINDIR)
+ install -m 755 $(TARGETS) $(BINDIR)
+
+clean:
+ -rm -f $(TARGETS) *.o
+
+indent:
+ ../../scripts/Lindent $(wildcard *.[ch])
+
+relabel:
+
diff --git a/libsepol/utils/chkcon.c b/libsepol/utils/chkcon.c
new file mode 100644
index 0000000..baa5117
--- /dev/null
+++ b/libsepol/utils/chkcon.c
@@ -0,0 +1,44 @@
+#include <sepol/sepol.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+void usage(char*) __attribute__((noreturn));
+
+void usage(char *progname)
+{
+ printf("usage: %s policy context\n", progname);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+
+ if (argc != 3)
+ usage(argv[0]);
+
+ fp = fopen(argv[1], "r");
+ if (!fp) {
+ fprintf(stderr, "Can't open '%s': %s\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+ if (sepol_set_policydb_from_file(fp) < 0) {
+ fprintf(stderr, "Error while processing %s: %s\n",
+ argv[1], strerror(errno));
+ exit(1);
+ }
+ fclose(fp);
+
+ if (sepol_check_context(argv[2]) < 0) {
+ fprintf(stderr, "%s is not valid\n", argv[2]);
+ exit(1);
+ }
+
+ printf("%s is valid\n", argv[2]);
+ exit(0);
+}